0x01 前言
好久不见。最近有好多想写但没有发的内容,内容很杂很多,一直想找个空闲的时间整理一下。在连续熬了两个通宵之后下定决心,先把最近半生不熟的rust区块链部分给整理一下。
0x02 P2P网络核心概念及应用
1.基本概念
p2p网络是一种分布式系统,可以在网络中的不同计算机间共享资源,比如带宽、cpu等。应用最广泛的就是区块链技术
在p2p网络中,需要清楚以下最基本的两个概念
1.传输协议: 底层使用的是传输层的tcp/udp协议,但会在这个基础上运用多路复用 应用多种应用层协议
2.节点标识: 类似于区块链中的钱包地址,p2p的每个node都需要一个标识,节点标识是通过非对称公钥加密哈希而来
2.程序
我们来着手一个最简单的例子,ping案例
cargo new ping-project
在配置文件中加入如下依赖
[dependencies]
libp2p = "0.46"
tokio = { version = "1.19", features = ["full"] }
如果构建有问题的可以把libp2p的版本换成0.53.1
main.rs
use std::error::Error;
use libp2p::{
futures::StreamExt,
identity,
ping::{Ping, PingConfig},
swarm::SwarmEvent,
Multiaddr, PeerId, Swarm,
};
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
// 生成认证密钥
let key_pair = identity::Keypair::generate_ed25519();
// 基于密钥对的公钥,生成节点唯一标识peerId
let peer_id = PeerId::from(key_pair.public());
println!("节点ID: {peer_id}");
// 声明Ping网络行为
let behaviour = Ping::new(PingConfig::new().with_keep_alive(true));
// 传输
let transport = libp2p::development_transport(key_pair).await?;
// 网络管理模块
let mut swarm = Swarm::new(transport, behaviour, peer_id);
// 在节点随机开启一个端口监听
swarm.listen_on("/ip4/0.0.0.0/tcp/0".parse()?)?;
// 从命令行参数获取远程节点地址,进行链接。
if let Some(remote_peer) = std::env::args().nth(1) {
let remote_peer_multiaddr: Multiaddr = remote_peer.parse()?;
swarm.dial(remote_peer_multiaddr)?;
println!("链接远程节点: {remote_peer}");
}
loop {
// 匹配网络事件
match swarm.select_next_some().await {
// 监听事件
SwarmEvent::NewListenAddr { address, .. } => {
println!("本地监听地址: {address}");
}
// 网络行为事件
SwarmEvent::Behaviour(event) => println!("{:?}", event),
_ => {}
}
}
}
当然你也可以分两块写,一个server端,一个client端
在配置文件中写入
[[bin]]
name = "server"
path = "src/server.rs"
[[bin]]
name = "client"
path = "src/client.rs"
我这里写的是第二种
cargo run --bin server
cargo run --bin client /ip4/127.0.0.1/tcp/41677
0x03 区块和区块链
初步了解了P2P,那么接下来将深入区块链
区块链在我的理解上,是一个去中心化、P2P形式的分布式数据库
首先我们了解一下区块
区块存储了基本的信息,比如交易,一个个交易的区块也就构成了狭义理解的区块链
这里我们先暂且不记录过多的信息,搭建一个初步的框架
区块与区块头如下
后面需要计算hash
接下来将从头建造区块,以及实现创世块,创世块prev_hash无值
设置完区块,将继续打造区块链
挖矿模块->把区块加入区块链中
最后完成初始化
cargo run --example gen_bc --quiet RUST_LOG=info
目录结构如下
0x04 POW 工作量证明
在0x03部分我们完成了初步的区块链实现,但挖矿只需赋值即可,所以我们需要通过工作量证明来
按照pow的思路: ->提出一个计算难题->计算不对称性,使满足目标哈希->验证->区块链增加
目前市面上广为流传的便是:以 SHA256 算法计算一个目标哈希,使得这个哈希值符合前 N 位全是 0。
这个N的数值,从某种意义上来说也可以量化成计算的难度
我们先把blockheader值改改
那接下来我们就可以详细讲讲bits和nonce的含义了
bits:计算难度,区块hash值的前多少位是 0。
nonce:记录满足bits难度,重复计算的次数。
一般来说,计算的区块hash值前多少位是被硬编码的,比如这里我们设置成7
const CURR_BITS: usize = 8;
新建一个pow.rs,用以计算哈希值
进行运行
cargo run --example gen_bc --quiet RUST_LOG=info
expected `Result<String>`, but found `Result<Vec<u8>>`
可以看到,存在nonce值了
0x05 持久化
之前的区块链是存储在内存中的,无法持久化存储。
搜罗了大部分网上的教程,最简单的方法就是将区块链存储在硬盘中,默认使用默认使用KV数据库sled。
数据库的结构即区块链的结构
好久没用非关系数据库,这次我们选择rust的嵌入式数据库好伙伴!sled!
首先构造一下数据库结构
实现数据库的基本功能
实现区块链与数据库的对接
完成代码见后文,这里我们先测试一下
cargo run --example gen_bc --quiet RUST_LOG=info
可以看到这里测试成功
0x06 总结
这只是实现了区块链的初步功能,还有钱包、交易等功能没有实现,笔者也在慢慢探索,如果感兴趣的话请后续敬请关注吧(后续出点src内容再出区块链了)
初步代码地址
https://github.com/jiankeguyue/Rust_BlockChain
原文始发于微信公众号(剑客古月的安全屋):区块链-RUST实战篇(1)
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论