用Rust实现区块链 - 3 持久化
前两部分我们都是将区块链存储在内存中。从这一部分开始,我们将区块链持久化到硬盘中,默认使用KV数据库sled。
数据库结构
KEY |
VALUE |
tip_hash |
区块链中最后加入块的hash值 |
height |
区块链中的高度 |
blocks:{hash} |
区块的hash值,blocks为前缀。 |
pub const TIP_KEY: &str = "tip_hash";
pub const HEIGHT: &str = "height";
pub const TABLE_OF_BLOCK: &str = "blocks";
Storage Trait
考虑到存储的可扩展性,将来使用其他KV数据库,如:RocksDB。我们定义了storage trait。
pub trait Storage: Send + Sync + 'static {// 获取最后一个块的hash值fn get_tip(&self) -> Result<Option<String>, BlockchainError>;// 获取一个区块fn get_block(&self, key: &str) -> Result<Option<Block>, BlockchainError>;// 获取区块链的高度fn get_height(&self) -> Result<Option<usize>, BlockchainError>;// 以事务的方式更新区块链 fn update_blocks(&self, key: &str, block: &Block, height: usize);// 获取区块的迭代器fn get_block_iter(&self) -> Result<Box<dyn Iterator<Item = Block>>, BlockchainError>;
}
// 定义区块的迭代器
pub struct StorageIterator<T> {data: T
}impl<T> StorageIterator<T> {pub fn new(data: T) -> Self {Self { data }}
}// T泛型需要满足Iterator约束
// T的item类型需要满足能转换成Block
impl<T> Iterator for StorageIterator<T>
whereT: Iterator,T::Item: Into<Block>
{type Item = Block;fn next(&mut self) -> Option<Self::Item> {self.data.next().map(|v| v.into())}
}
Sled的实现
pub struct SledDb {// seld::Dbdb: Db
}impl SledDb {pub fn new(path: impl AsRef<Path>) -> Self {Self {db: sled::open(path).unwrap()}}fn get_full_key(table: &str, key: &str) -> String {format!("{}:{}", table, key)}
}impl Storage for SledDb {......fn update_blocks(&self, key: &str, block: &Block, height: usize) {// 使用事务let _: TransactionResult<(), ()> = self.db.transaction(|db| {let name = Self::get_full_key(TABLE_OF_BLOCK, key);db.insert(name.as_str(), serialize(block).unwrap())?;db.insert(TIP_KEY, serialize(key).unwrap())?;db.insert(HEIGHT, serialize(&height).unwrap())?;db.flush();Ok(())});}fn get_block_iter(&self) -> Result<Box<dyn Iterator<Item = Block>>, BlockchainError> {let prefix = format!("{}:", TABLE_OF_BLOCK);let iter = StorageIterator::new(self.db.scan_prefix(prefix));Ok(Box::new(iter))}
}
修改区块链
// 默认使用sled数据库
pub struct Blockchain<T = SledDb> {storage: T,tip: Arc<RwLock<String>>,height: AtomicUsize,
}impl<T: Storage> Blockchain<T> {pub fn new(storage: T) -> Self {// 如果数据库中有tip值,则加载到内存。// 否则创建一个创世块,并更新到数据库中。if let Ok(Some(tip)) = storage.get_tip() {let height = storage.get_height().unwrap();Self {storage,tip: Arc::new(RwLock::new(tip)),height: AtomicUsize::new(height.unwrap()),}}else {let genesis_block = Block::create_genesis_block(CURR_BITS);let hash = genesis_block.get_hash();storage.update_blocks(&hash, &genesis_block, 0 as usize);Self {storage,tip: Arc::new(RwLock::new(hash)),height: AtomicUsize::new(0),}}}pub fn mine_block(&mut self, data: &str) {let block = Block::new(data, &self.tip.read().unwrap(), CURR_BITS);let hash = block.get_hash();self.height.fetch_add(1, Ordering::Relaxed);self.storage.update_blocks(&hash, &block, self.height.load(Ordering::Relaxed));let mut tip = self.tip.write().unwrap();*tip = hash;}pub fn blocks_info(&self) {let blocks = self.storage.get_block_iter().unwrap();for block in blocks {info!("{:#?}", block);}}
}
验证
RUST_LOG=info cargo run --example gen_bc --quiet
INFO blockchain_rust_part_3::blocks::blockchain: Block {header: BlockHeader {timestamp: 1650259594,prev_hash: "",bits: 8,nonce: 233,},data: "创世区块",hash: "00d76473e80522e336a1078227d10d599190d8ef6877fa1d6fa980d692ef3c18",
}
第一次执行,创建了创世块,且存入到了数据库中。再次执行,取出的区块信息应该与第一次执行时创建的区块一样。大家可以自己验证。
工程结构
完整代码:
https://github.com/Justin02180218/blockchain_rust
更多文章,请关注公众号:coding到灯火阑珊
用Rust实现区块链 - 3 持久化相关推荐
- 蚂蚁区块链-CONFIDE-ACM SIGMOD 20
论文名称:<Confidentiality Support over Financial Grade Consortium Blockchain> 论文地址:https://dl.acm. ...
- Web3 开发者必备手册:盘点 5 种最佳区块链编程语言
一份必备的区块链开发语言列表,帮助 Web3 创业者快速启动并创建一个项目. Rust - 用于区块链开发的最佳编程语言 Rust 是一种相对年轻的编程语言,但已经在区块链行业中证明了它的效率.不久前 ...
- 用Go语言建立一个简单的区块链part3:持久化和命令行接口
持久化和命令行接口 引言 到目前为止,我们已经构建了一个有工作量证明机制的区块链.有了工作量证明,挖矿也就有了着落.虽然目前距离一个有着完整功能的区块链越来越近了,但是它仍然缺少了一些重要的特性.在今 ...
- 用 Go 构建一个区块链 -- Part 3: 持久化和命令行接口
翻译的系列文章我已经放到了 GitHub 上:blockchain-tutorial,后续如有更新都会在 GitHub 上,可能就不在这里同步了.如果想直接运行代码,也可以 clone GitHub ...
- 从0到1简易区块链开发手册V0.3-数据持久化与创世区块
Author: brucefeng Email: brucefeng@brucefeng.com 编程语言:Golang 1.BoltDB简介 Bolt是一个纯粹Key/Value模型的程序.该项目的 ...
- 区块链生态系统将崩溃、Rust 超越 Go、无服务器成主导,这十大计算机预测将成真?...
[编者按]在IT圈有句名言:"活到老,学到老".短短 6 字便道出技术发展速度之快.移动互联网.云计算.大数据.人工智能等技术革新在过去十年推动着时代巨轮不断向前迈步.接下来,我们 ...
- 区块链常用序列化分析
parity开源解析 parity-scale-codec 用于Parity Substrate框架中的类型的SCALE(Simple Concatenated Aggregate Little-En ...
- libra区块链技术白皮书-中文部分翻译版
2019年6月18日facebook发布了libra区块链,目标是做一个全球货币和支付工具.最近花了一些时间来研究这个libra,官网上有白皮书的中文版,但没有技术白皮书的中文版,因此花了一些时间来做 ...
- 区块链入门 第七部分 以太坊
以太坊 以太坊相关导航 以太坊(Ethereum)是一个开源的有智能合约功能的公共区块链平台.通过其专用加密货币以太币(Ether)提供去中心化的虚拟机("以太虚拟机" Ether ...
最新文章
- Kibana:分析及可视化日志文件
- 类选择器和所作用的标签一起写为什么不起作用? - CSDN博客
- CVPR和ICLR双榜公布,最离谱审稿人竟然没读论文!
- Google 全球员工围攻 Google!
- hello this Word ! I'm coming!
- 机器学习中的损失函数
- 与时代并肩的数字创新者
- Java通过HighCharts导出图表
- 普通调幅(AM)与抑制载波双边带调幅(DSB)matlab编程实现
- nginx配置 vue打包后的项目 解决刷新页面404问题|nginx配置多端访问
- 计算机中年级排名怎么操作,智学网如何查看年级排名 智学网看年级排名方法【详解】...
- (转)星巴克其实是靠大数据盈利的!
- LaTeX最全的数学符号大全(更新中…… )
- 几本开关电源书籍 pdf格式 (来源中国电子开发网)
- 360浏览器小号多开使用
- mysql之事务 锁(三)
- 捋一捋DSP里的重叠保留法
- 教你修改电脑mac地址图解教程
- 系统扫描修复cmd命令
- Serv-U 安装配置以及外网访问使用
热门文章
- 永远不要在MySQL中使用UTF-8
- 2019_GDUT_新生专题V算法优化 F. Expedition POJ 2431
- python批量修改列名_pandas修改DataFrame列名的实现方法
- 计算机正确的坐姿教案,礼仪课坐姿教案.doc
- Java实现给图片局部打马赛克
- python开发项目经历_Python开发工程师岗位项目经历怎么写
- [Swift]LeetCode41. 缺失的第一个正数 | First Missing Positive
- 如何用Python画一只狗狗——turtle基础
- lower_bound,upper_bound的第四个参数的用法
- Velocity模板语言(VTL):说明