狗哥区块链与AI精品内容集@NonceGeek

2025年03月28日更新 75 人订阅
原价: ¥ 20 限时优惠
专栏简介 「造」最关键的是什么?| Hackathon 漫游指南(贰) Why Hackathon?| Hackathon 漫游指南(壹) 设计「众人维护」的 BuidlerBoard | BeWater.xyz Movement 白皮书中文版 Rebuidl RSS 生产因素与反生产因素 | 独立黑客创业手册(陆) 组织 | 独立黑客创业手册(伍) 生产 | 独立黑客创业手册(肆) 销售 | 独立黑客创业手册(叄) 最优先的能力 | 独立黑客创业手册(贰) 为什么从独立黑客开始 | 独立黑客创业手册(壹) Aptos Token Object V2 | Move dApp 极速入门(贰拾肆) 可編程交易塊 | Move dApp 極速入門(貳拾叁) Aptos 密鑰輪換 | Move dApp 極速入門(貳拾貳) Aptos 对象模型 | Move dApp 极速入门(贰拾壹) Aptos Moveflow SDK使用指南 | Move dApp 极速入门(贰拾) Sui 上简单 Swap 的实现 | Move dApp 极速入门(拾玖) 用 Elixir 交互 Aptos | Move dApp 极速入门(拾捌) Sui 链上数据查询 | Move dApp 极速入门(拾柒) SUI 合约测试攻略 | Move dApp 极速入门(拾陆) Sui 数据类型详解 | Move dApp 极速入门(拾伍) Airdropper Contract in Aptos | Move dApp 极速入门(拾肆) Sandwich合约源码解析 | Move dApp 极速入门(拾叁) Sui 极速上手 | Move dApp 极速入门(拾贰) scaffold-aptos 脚手架 | Move dApp 极速入门(拾壹) 对 DID Document 的思考 | Move dApp 极速入门(九) DID中地址聚合器的实现 | Move dApp 极速入门(八) 值的存取应用3.0 | Web3.0 dApp 开发(五) 合约数据类型综述 | Move dApp 极速入门(四) 操作资源 | Move dApp 极速入门(三) 第一个 Move dApp | Move dApp 极速入门(二) Hello Move | Move dApp极速入门(一) Staker | Web3.0 dApp 开发(九) Token 自动售卖机 | Web3.0 dApp 开发(七) SVG NFT 全面实践 | Web3.0 dApp 开发(六) 值的存取应用2.0 | Web3.0 dApp 开发(四) 值的存取应用1.0 | Web3.0 dApp开发(三) Scaffold-eth 快速上手 | Web3.0 dApp 开发(二) eth.build 快速上手 | Web3.0 dApp 开发(一) 1 小时理解比特币系统 【NonceGeek Workshop 0x01总结】基于链上数据生成游戏地图 Remix 完全本地化部署 NFT:实体与虚拟载体的主与辅 | 狗哥的元宇宙思辨(一) Web3Camp 内容大全@NonceGeek 用 Python 创建一条 Pow 区块链(上) 区块链与共识机制演变史 基于 Etherscan 实现 Blockchain Syncer 【论文分享】去中心化社会:寻找 Web3 的灵魂(上) 【论文分享】去中心化社会:寻找 Web3 的灵魂(下) Ted Yin | 2021 年的区块链基础设施将是什么? 0. 公链、联盟链与分布式未来(全文) 基于 Infura 与 Web3py 部署调用 Hello 合约全过程 | 以太坊开发极速入门 太上中的基因设计与Binary | 函数式与区块链(一) 理解以太坊合约数据读取过程 | 函数式与区块链(二) Hello, Ink! | 用 Rust 写智能合约(一) Mapping 数据结构 | 用 Rust 写智能合约(二) 用 Rust 程序和 Webase 交互 | Rust 学习笔记(四) 用 Sqlite 存储 WeId | Rust 学习笔记(五) 链上注册WeId与错误处理 | Rust 学习笔记(六) WeId 链上创建与本地存储的完整闭环 | Rust 学习笔记(七) 以太坊上的核心开发者 Austin | 以太坊上的最佳开发实践 1. FISCO BCOS 开发环境节点搭建全攻略 伪代码简述 ECDSA 签名过程 | 联盟链开发 WeIdentity 源码分析 | 狗哥解码 WeIdentity 源码分析 | 狗哥解码 FISCO BCOS 介绍 | 联盟链开发 给Remix升个级 | 联盟链开发 2. 控制台的安装与使用 3. 【实验】补全一个区块链应用 4. 控制台的Web化 5. Web化控制台2.0:打造团队共用区块链学习平台 6. 使用脚手架快速搭建 Java DApp 【视频+文字】分布式思维 Rebuidl RSS (EN)

WeId 链上创建与本地存储的完整闭环 | Rust 学习笔记(七)

  • 李大狗
  • 发布于 2021-06-18 11:35
  • 阅读 6098

Rust 实践走起来

系列简介: 狗哥 Rust 学习笔记系列是大狗为对抗 Rust 陡峭的学习曲线而推出的 Rust 学习系列,具备如下原则:

  1. 循序渐进原则

按照阶梯法则(下一篇的难度是上一篇难度+1)原则进行设计,让学习 Rust 跟打游戏一样简单。

  1. 单一知识点原则

一篇文章只讲一个一个知识点,保证简单性与专注性。

  1. 实用原则

所有案例均是真实实践案例,实用性超强。

在之前的两篇文章中,我们分别介绍了:

将二者整合,我们可以得到 WeId 的链上生成 — 本地存储的完整闭环。这个项目我已推送到 Github 上并补充了 README,欢迎 STAR~

https://github.com/leeduckgo/weid-rust-sample

项目结构

.
├── Cargo.lock
├── Cargo.toml
├── README.md
├── bin # bin 中放置的是 diesel 二进制软件体
├── diesel # diesel 开头均为数据库相关
├── diesel_cli
├── diesel_derives
├── diesel_migrations
├── ethereum # 以太坊包,为之后本地生成-链上注册做准备
├── model # 同上
├── examples.db # sqlite 数据库
├── migrations # 数据库记录文件
├── src # 主文件
|     ├── main.rs
|     └── models.rs
├── weid-light-client # 解耦轻客户端,对接 weid-rest-service 服务
└── target # 编译后的文件

当前流程

  1. 调用 WeIdGenerator,在链上注册WeIdentity

借助了reqwest库,详细使用方法见:

链上注册WeId与错误处理 | Rust 学习笔记(六)

weid-light-client/src/weid_generator.rs源码:

use serde_json::{Value};
use thiserror::Error;

/// Provide an implementation for the default() method:
/// https://doc.rust-lang.org/stable/core/default/trait.Default.html
#[derive(Default)]
pub struct WeIdGenerator{
    endpoint_url: String,
    weid: String, 
}

impl WeIdGenerator{
    pub fn new(endpoint_url: String) -> WeIdGenerator {
        WeIdGenerator {endpoint_url, ..Default::default()}
    }
    /// String or &str?
    /// Ref: https://zhuanlan.zhihu.com/p/123278299
    /// 显然,这取决于很多因素,但是一般地,保守来讲,如果我们正在构建的API不需要拥有或者修改使用的文本,
    /// 那么应该使用&str而不是String。
    /// 等一下,但是如果这个API的调用者真的有一个String并且出于某些未知原因无法将其转换成&str呢?完全没有问题。
    /// Rust有一个超级强大的特性叫做deref coercing,这个特性能够允许把传进来的带有借用操作符的String引用,
    /// 也就是&String,在API执行之前转成&str。我们会在另一篇文章里介绍更多地相关细节。
    pub fn generate_local(&mut self, chain_id: i32, addr: &str) -> String {
        self.weid = "did:weid:".to_string() + &chain_id.to_string() + ":" + addr;
        // Ref: https://stackoverflow.com/questions/38304666/how-to-define-a-copyable-struct-containing-a-string
        // String is copyable, use .clone()
        // String is not implicitly copyable, because that would cause non-obvious memory allocations to occur
        self.weid.clone()
    }

    /// create weid online.
    pub fn create_weid_online(&self) -> Result<Value, GenerateWeIdError>{
        let response = self.call_create_weid()?;
        let resp = self.str_to_json(&response)?;
        Ok(resp)
    }

    fn str_to_json(&self, payload: &str) -> Result<Value, serde_json::Error> {
        serde_json::from_str(payload)
    }
    pub fn call_create_weid(&self) -> Result<String, reqwest::Error> {
        let mut url =self.endpoint_url.to_string();
        url += &"/weid/api/invoke".to_string();
        // ::blocking:: to block
        let response = reqwest::blocking::Client::new()
        .post(&url)
        .json(&serde_json::json!({
            "functionArg": {},
            "transactionArg": {},
            "v": "1.0.0",
            "functionName": "createWeId"
        }))
        .send()?
        .text();

        response
    }
}
/// multi error handle:
/// https://my.oschina.net/jmjoy/blog/3190024
#[derive(Error, Debug)]
pub enum GenerateWeIdError {
    #[error("req error")]
    RequestError(#[from] reqwest::Error),
    #[error("parse error")]
    ParseError(#[from] serde_json::Error),
}
  1. create_weid_online()函数结果处理,见src/main.rs
fn gen_weid_online_and_save(weid_generator: WeIdGenerator) -> Result<Value, GenerateWeIdError>{
  let result = weid_generator.create_weid_online();

  match result {
    Ok(payload) => {
      // TODO
      //weid = payload |> to_weid
      //vec_weid = weid |> vec
      // save to local sqlite
      // info
      Ok(payload)
    },
    Err(e) => {
      info!("{}", e);
      Err(e)
    }
  }
}
  1. 定义数据结构与数据 CRUD 操作

详见:

用 Sqlite 存储 WeId | Rust 学习笔记(五)

src/models.rs源码:

use chrono::NaiveDateTime;
#[cfg(test)]
use diesel::debug_query;
use diesel::insert_into;
use diesel::prelude::*;

use std::env;
use dotenv::dotenv;

#[cfg(test)]
use diesel::sqlite::Sqlite;

pub mod schema {
    diesel::table! {
        weids {
            id -> Integer,
            chain_id -> Integer,
            addr -> Text,

            created_at -> Timestamp,
            updated_at -> Timestamp,
        }
    }
}

use schema::weids;

#[derive(Insertable)]
#[table_name = "weids"]
pub struct NewWeId {
    pub chain_id: i32,
    pub addr: String,
}

#[derive(Queryable, PartialEq, Debug)]
pub struct WeId {
    pub id: i32,
    pub chain_id: i32,
    pub addr: String,

    pub created_at: NaiveDateTime,
    pub updated_at: NaiveDateTime, 
}

pub fn insert_default_values(conn: &SqliteConnection) -> QueryResult<usize> {
    use schema::weids::dsl::*;

    insert_into(weids).default_values().execute(conn)
}

pub fn establish_connection() -> SqliteConnection {
    dotenv().ok();

    let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
    SqliteConnection::establish(&database_url)
        .unwrap_or_else(|_| panic!("Error connecting to {}", database_url))
}

pub fn save_weid(conn: &SqliteConnection, c_id: i32, address: &str) -> usize {

    let new_weid = NewWeId {chain_id: c_id, addr: address.to_string()};

    diesel::insert_into(weids::table)
        .values(&new_weid)
        .execute(conn)
        .expect("Error saving new weid")
}
  1. 补充 2 中的 TODO 部分
fn gen_weid_online_and_save(weid_generator: WeIdGenerator) -> Result<Value, GenerateWeIdError>{
    let result = weid_generator.create_weid_online();

    match result {
        Ok(payload) => {
            // str handle
            let weid_str: String = 
                payload["respBody"]
                .to_string()
                .replace("\"", "");
            // str to vec
            let vec: Vec<&str> = 
                weid_str
                .split(":")
                .collect();

            let chain_id: i32 = vec[2].parse().unwrap();
            let addr: &str = vec[3];
            // create data
            let sqlite_conn = models::establish_connection();

            models::save_weid(&sqlite_conn, chain_id, addr);
            info!("gen and save weid to local {}.", weid_str);
            Ok(payload)
        },
        Err(e) => {
            info!("{}", e);
            Err(e)
        }
    }
}
  1. 在 main 函数中调用
fn main(){
    pretty_env_logger::init();
    // 从环境变量中拿取 "WEID_URL"
    let url = env::var("WEID_URL").expect("DATABASE_URL must be set");
    let weid_generator = WeIdGenerator::new(url.to_string());
    gen_weid_online_and_save(weid_generator);
}

运行项目

  1. 初始化数据库
./bin/diesel database reset
  1. 设置环境变量
# 推荐使用direnv
export DATABASE_URL="examples.db"
export BACKEND="sqlite"
export WEID_URL=<weid-rest-service url>
  1. 运行项目
RUST_LOG=info cargo run

目前会在链上创建托管型WeId并存储在本地的Sqlite数据库中。

image-20210617172840467

升级方向

  1. 添加「私钥不出域」创建WeId的方式
  2. 实现 WeIdentity Document的同步操作
  3. 目前项目开发需要先启动WeIdentity-Rest-Service,考虑设计 Mock 接口,方便开发。
点赞 1
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论