区块链相关概念
概念不说人话,感觉不如下边实例更好理解qwq
定义
说点人话,就是一种技术,能够实现极高信用保证的东西qwq
区块链相关技术:密码学、控制论、博弈论、分布式系统、数字货币
主要用于去中心化分布式记账本技术,应用:金融、贸易、征信、物联网、共享经济blabla...
区块链常见定义方式:
- 不依赖于第三方,通过自身分布式节点进行网络数据存储、验证、传递、交流
- 分布式开放性的大型网络记账簿,任何人都可以在任何时间进行操作
- 分布式、去中心化的计算与存储架构
区块链的特征:
- 去中心化
- 开放透明
- 安全性
- 匿名性
举例,比特币交易流程:
- 发起事务请求
- 请求事务广播到网络p2p节点
- 节点使用加密算法验证
- 验证成功,该事务被标识为一个新区块
- 新区块添加到现有区块中
分类
公有链
- 所有人均可参与
- 完全去中心化
- 效率很低
全世界都可以访问,比如比特币的区块链,不过区块链维护要钱,所以公有链不会太多qwq
联盟链
- 记账权由部分组织共享
- 不完全去中心化
- 效率较高
可以有几个主节点,这些主节点不挂就行。一般由一些组织成员共享(比如几家快递公司共享物流信息什么的),这样就可以每个成员出一部分钱来维护了,区块链最常见的是联盟链。
私有链
- 记账权集中到一点
- 完全中心化
- 效率最高
没什么意义,自己玩就没意思了qwq
| 公有链 | 联盟链 | 私有链 | |
|---|---|---|---|
| 参与者 | 所有人 | 联盟成员 | 所有者 |
| 记账人 | 所有人 | 成员协商确定 | 所有者 |
| 中心化程度 | 完全去中心化 | 部分中心节点 | 完全中心化 |
| 典型场景 | 加密货币 | 物流 | 大型组织机构 |
| 交易可视化 | 完全 | 不可视 | 视情况而定 |
结构
区块链,看名字就是块加上链表嘛qwq
一些不说人话的概念:
- 交易(Transaction):一次操作导致账本状态的改变,如插入一条数据。
- 区块(Block):记录一段时间内的交易信息和结果,由头和主体组成,主体记录交易信息,头部记录链相关信息。
- 链(Chain):区块按照发生顺序串联,是整个状态变化的日志。
每个块(链表节点)包含结构:
- timestamp: 区块产生时间戳
- nonce: 随机值,与区块头的hash值共同证明计算量(工作量),用于计算哈希(详见代码实现)
- data: 区块链上存储的数据(默克尔树存储)
- previousHash: 上一个区块的hash
- currentHash: 本区块链的hash,由上述几个属性进行哈希计算而得
挖矿是什么
这是一种基于 PoW(Proof of Work) (即工作量证明)机制的操作,知名货币比特币、以太币都使用了PoW机制。
每个区块链都运行在一个共识机制上,共识机制是该区块链网络上所有节点的协议,目的是证明在该区块链操作的真实性:
- 确保交易的真实性
- 防止有人恶意篡改帐本
- 确认交易
- 避免双重支付
我们拿比特币来举例:比特币网路中的人被称为矿工,使用算力、电力、时间来计算PoW的过程称为挖矿,借此开采新的区块,终极目标是争夺每个区块的记帐拥有权,并取得奖励(获得比特币)。
PoW机制认为,网络中有超过51%的节点认为操作是真实的,就可以证明某操作是真实的。它被设计为要消耗大量算力,可以有效防止数据被篡改,毕竟,不可能有人的算力能超过这个巨大的网络中51%的计算机。(换句话说,篡改要消耗的算力都超过正常挖矿需要的算力了,有那能力去改数据还不如老实去挖矿)。
PoW缺点也是显而易见的,就是要消耗大量毫无意义的算力,以及,假如真的有人掌握超过全网半数以上的算力,还是可以随意篡改数据的(虽然可能性不大qwq)。
当然,共识机制不只有PoW一种,比较出名的还有PBFT,PoS,blabla...就不细说了qwq
代码实现简易区块链
基本结构
Java代码实现简易的区块链,结构如上文所述(为什么是java,因为是比着java的例子抄的嘤~)
哈希
我们要保证,当前区块的previousHash和前一个区块的currentHash始终保持一致,这样才能认为这个区块链是有效的。
将区块链所有的信息转换成一个哈希,通过这个哈希的值来验证当前块是否被篡改过。
挖矿过程的设计
我们要设定一种方法,它可以消耗一部分算力,使得篡改区块产生一定成本。(注意这个操作本身是没有意义的,目的就是让区块变得难以篡改)
还记得刚刚定义的随机数nonce吗,它的作用就是保证每次哈希计算值都不同。
我们设定一个难度difficulty,不断计算区块的哈希(每次nonce+1),直到区块hash值前difficulty位为0时才认为这个哈希是有效的。这个不断计算的过程就称为挖矿。
这样简单想一下,当我们篡改某个块的内容时,重新计算它的hash需要一个复杂的挖矿过程。由于它后一个块也有一个previousHash字段被改变,要保证链的有效性,我们也需要对后一个块进行挖矿,后一个块的后一个块也要挖矿...这样篡改的成本就非常高了。
代码
首先我们按上文所述定义一个区块:
Block.java:
package blockchain;
import java.security.MessageDigest;
public class Block {
private static int currentId = 0;
public int id; // 唯一标识
public long timestamp; // 时间戳
public String currentHash; // 当前块hash
public String previousHash; // 前一个块hash
public String data; // 当前块信息
public int nonce; // 用于计算hash的随机值
public Block(String previousHash, String data) {
this.id = currentId++;
this.timestamp = System.currentTimeMillis();
this.previousHash = previousHash;
this.data = data;
this.currentHash = calculateHash();
}
/**
* 将头部信息转换成16进制哈希值
*/
public String calculateHash() {
StringBuffer hexString = new StringBuffer();
try {
String inpuString = Integer.toString(id) + previousHash + Long.toString(timestamp) + data + Integer.toString(nonce);
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] hash = digest.digest(inpuString.getBytes("UTF-8"));
for (int i = 0; i < hash.length; i++) {
String hex = Integer.toHexString(0xff & hash[i]);
if (hex.length() == 1) hexString.append('0');
hexString.append(hex);
}
} catch (Exception e) {
e.printStackTrace();
}
return hexString.toString();
}
/**
* 挖矿过程计算哈希,不断变换nonce值并计算哈希,直到哈希值第一位开始的difficulty个字符为0
* @param difficulty 挖矿难度,设定前几位为0
*/
public void mineBlock(int difficulty) {
String target = new String(new char[difficulty]).replace('\0', '0');
while (!currentHash.substring(0, difficulty).equals(target)) {
nonce++;
currentHash = calculateHash();
}
System.out.println("Block mined: " + currentHash);
}
public String toString() {
return "Block #" + id + "\r\n" +
"Timestamp: " + timestamp + "\r\n" +
"Previous Hash: " + previousHash + "\r\n" +
"Current Hash: " + currentHash + "\r\n" +
"Data: " + data + "\r\n" +
"Nonce: " + nonce + "\r\n";
}
}
接下来我们通过这些区块组建一个区块链,并提供一些验证机制:
BlockChain.java:
package blockchain;
import java.util.ArrayList;
public class BlockChain {
public static int difficulty = 2;
public ArrayList<Block> chain = new ArrayList<Block>();
public void genernateBlockChain() {
Block b1 = new Block(null, "First block.");
b1.mineBlock(difficulty);
chain.add(b1);
System.out.println(b1.toString());
Block b2 = new Block(b1.currentHash, "Second block.");
b2.mineBlock(difficulty);
chain.add(b2);
System.out.println(b2.toString());
System.out.println("Current BlockChain valid:" + validateChain(this.chain));
}
/**
* 验证区块是否有效,防止被篡改
* 1. 前后衔接是否合法
* 2. 当前块是否有效
* @param current 当前区块
* @param previous 前一个区块
* @return
*/
public static Boolean validateBlock(Block current, Block previous) {
if (!current.previousHash.equals(previous.currentHash)) {
return false;
}
if (!current.currentHash.equals(current.calculateHash())) {
return false;
}
return true;
}
/**
* 验证链是否有效,验证所有区块有效性即可
* @param chain 区块链
* @return
*/
public static Boolean validateChain(ArrayList<Block> chain) {
Block previous = chain.get(0);
for (int i = 1; i < chain.size(); i++) {
Block current = chain.get(i);
if (!validateBlock(current, previous)) {
return false;
}
previous = current;
}
return true;
}
}
调用genernateBlockChain方法,控制台输出:
Block mined: 00e8eed71c98e68668f37e23d6e3af8891b59fc81ae3b7725b4f546f11192ae6
Block #0
Timestamp: 1656863294128
Previous Hash: null
Current Hash: 00e8eed71c98e68668f37e23d6e3af8891b59fc81ae3b7725b4f546f11192ae6
Data: First block.
Nonce: 90
Block mined: 00b02c57715baba6c263adf075d5fd01af0d2ce45f72a60b4161e1d715543b0c
Block #1
Timestamp: 1656863294149
Previous Hash: 00e8eed71c98e68668f37e23d6e3af8891b59fc81ae3b7725b4f546f11192ae6
Current Hash: 00b02c57715baba6c263adf075d5fd01af0d2ce45f72a60b4161e1d715543b0c
Data: Second block.
Nonce: 392
Current BlockChain valid:true
应用实例:简易转账系统
RSA加密简介
首先需要了解一下RSA加密,拿之前蓝桥杯一个题一图看懂(看不懂也没事,知道密钥对干啥的就行qwq):
(放一下题解)
对于一个转账行为,用户持有公私密钥对,可以通过公钥来确定是哪个用户(这里为了简化流程,我们省去了签名的过程)。
代码实现
定义一个事务,即一个转账行为,包含转账相关信息,这里发送接收者实际上就是存储用户的公钥。
Transaction.java:
package blockchainApp;
public class Transaction {
public String sender; // 转账发出者
public String recipient; // 转账接收者
public float amount; // 转账金额
public Transaction(String from, String to, float value) {
this.sender = from;
this.recipient = to;
this.amount = value;
}
}
修改Block,使其存储信息为记账本(即Transection数组):
public ArrayList<Transaction> transactions; // 账本信息
// 另外在calculateHash方法中,把所有记账信息放入哈希计算即可,不贴详细代码了
for (Transaction transaction : transactions) {
inpuString += transaction.recipient + transaction.amount + transaction.sender;
}
定义用户(钱包?)存储密钥对和初始余额(实时余额应该通过区块链进行计算),具有向别人转账的方法。
Wallet.java:
package blockchainApp;
import java.util.ArrayList;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
public class Wallet {
public String publicKey; // 公钥
private String privateKey; // 私钥
public float balance; // 初始余额,实际余额会通过区块链计算得出
public ArrayList<Block> blockchain; // 区块链
public Wallet(float balance, ArrayList<Block> blockchain) {
generateRSAKey();
this.balance = balance;
this.blockchain = blockchain;
}
/**
* 生成RSA密钥对
*/
private void generateRSAKey() {
KeyPair keyPair;
try {
keyPair = KeyPairGenerator.getInstance("RSA").generateKeyPair();
privateKey = keyPair.getPrivate().toString();
publicKey = keyPair.getPublic().toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
/**
* 从区块链计算并获取当前账户的总余额
*/
public float getBalance() {
float total = this.balance;
for (Block block : blockchain) {
for (Transaction transaction : block.transactions) {
if (transaction.sender.equals(this.publicKey)) {
total -= transaction.amount;
}
if (transaction.recipient.equals(this.publicKey)) {
total += transaction.amount;
}
}
}
return total;
}
/**
* 向recipient转账amount金额
* @param recipient 接收者的RSA公钥
* @param amount
* @return 这次交易的记录
*/
public Transaction send(String recipient, float amount) {
if (amount > this.getBalance()) {
System.out.println("余额不足");
return null;
}
Transaction transaction = new Transaction(this.publicKey, recipient, amount);
// transaction.sign(privateKey);
return transaction;
}
}
之后就可以在BlockChain上做一些神奇操作BlockChainApp.java:
// 修改部分不多,粘部分代码
public ArrayList<Transaction> transactions = new ArrayList<Transaction>();
public void genernateBlockChain() {
Wallet Alice = new Wallet(100, this.chain);
Wallet Bob = new Wallet(100, this.chain);
System.out.println("Alice's initial balance: " + Alice.getBalance());
System.out.println("Bob's initial balance: " + Bob.getBalance() + '\n');
System.out.println("Alice is sending 10 coins to Bob..." + '\n');
Transaction t1 = new Transaction(Alice.publicKey, Bob.publicKey, 10);
if (t1 != null) {
transactions.add(t1);
}
Block b1 = new Block(null, this.transactions);
b1.mineBlock(difficulty);
chain.add(b1);
System.out.println(b1.toString());
System.out.println("Current BlockChain valid:" + validateChain(this.chain) + '\n');
System.out.println("Alice's balance: " + Alice.getBalance());
System.out.println("Bob's balance: " + Bob.getBalance() + '\n');
System.out.println("Bob is sending 20 coins to Alice..." + '\n');
// 踩坑记录:新建块时没有重置记账本
this.transactions = new ArrayList<Transaction>();
Transaction t2 = new Transaction(Bob.publicKey, Alice.publicKey, 20);
if (t2 != null) {
transactions.add(t2);
}
Block b2 = new Block(b1.currentHash, this.transactions);
b2.mineBlock(difficulty);
chain.add(b2);
System.out.println(b2.toString());
System.out.println("Current BlockChain valid:" + validateChain(this.chain) + '\n');
System.out.println("Alice's balance: " + Alice.getBalance());
System.out.println("Bob's balance: " + Bob.getBalance());
}
调用genernateBlockChain方法,控制台输出:
Alice's initial balance: 100.0
Bob's initial balance: 100.0
Alice is sending 10 coins to Bob...
Block mined: 00015b8569eb2adb86fac6a967e0ade85b271a708a136d8c3e7bc2e9d691b97d
Block #0
Timestamp: 1656864082866
Previous Hash: null
Current Hash: 00015b8569eb2adb86fac6a967e0ade85b271a708a136d8c3e7bc2e9d691b97d
Data: null
Nonce: 1567
Current BlockChain valid:true
Alice's balance: 90.0
Bob's balance: 110.0
Bob is sending 20 coins to Alice...
Block mined: 0080d90b23bc72f028e167050b9b116991d40634b6acd2aa64406f6445410b8b
Block #1
Timestamp: 1656864082946
Previous Hash: 00015b8569eb2adb86fac6a967e0ade85b271a708a136d8c3e7bc2e9d691b97d
Current Hash: 0080d90b23bc72f028e167050b9b116991d40634b6acd2aa64406f6445410b8b
Data: null
Nonce: 99
Current BlockChain valid:true
Alice's balance: 110.0
Bob's balance: 90.0
区块链demo
Github上一个用node写的简易区块链,感觉非常棒qwq
区块链Demo(Code): github.com/anders94/bl…
Demo: Blockchain Demo