IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 区块链 -> 用Rust实现区块链 - 3 持久化 -> 正文阅读

[区块链]用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> 
where
    T: 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::Db
    db: 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到灯火阑珊

  区块链 最新文章
盘点具备盈利潜力的几大加密板块,以及潜在
阅读笔记|让区块空间成为商品,打造Web3云
区块链1.0-比特币的数据结构
Team Finance被黑分析|黑客自建Token“瞒天
区块链≠绿色?波卡或成 Web3“生态环保”标
期货从入门到高深之手动交易系列D1课
以太坊基础---区块验证
进入以太坊合并的五个数字
经典同态加密算法Paillier解读 - 原理、实现
IPFS/Filecoin学习知识科普(四)
上一篇文章           查看所有文章
加:2022-05-05 11:24:16  更:2022-05-05 11:25:02 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 20:14:22-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码