【Rust】サーバが保持しているチェーンを返すメソッドを実装したい

サーバが保持しているブロックチェーンを返すメソッド

### axumでjsonを返す方法について

use axum::{routing::get, Json, Router};
use serde_json::{json, Value};

#[tokio::main]
async fn main() {
    let app = Router::new().route("/", get(||async {"Hello, World!"}))
            .route("/json", get(json));

    let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
    axum::serve(listener, app).await.unwrap();
}

async fn json() -> Json<Value> {
    Json(json!({"data": 42}))
}

### Struct(構造体)をjsonにしてAPIにする方法

use axum::{routing::get, Json, Router};
use serde_json::{json, Value};
use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize, Debug)]
struct Name {
    family: String,
    first: String,
    age: u32,
}

#[tokio::main]
async fn main() {
    let app = Router::new().route("/", get(||async {"Hello, World!"}))
            .route("/json", get(json));

    let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
    axum::serve(listener, app).await.unwrap();
}

async fn json() -> Json<Value> {
    let mut names: Vec<Name> = Vec::new();
    let n1 = Name { family: "Yamada".to_string(), first: "Taro".to_string(), age: 20 };
    let n2 = Name { family: "Tanaka".to_string(), first: "Hanako".to_string(), age: 18 };
    names.push(n1);
    names.push(n2);
    let data = serde_json::to_string(&names).unwrap();
    Json(json!(data))
}

“[{\”family\”:\”Yamada\”,\”first\”:\”Taro\”,\”age\”:20},{\”family\”:\”Tanaka\”,\”first\”:\”Hanako\”,\”age\”:18}]”

ここまではOKなんだけど、問題は、これをどうやって読み取ってNameごとに1行ずつ保存するかだな。。

【Rust】マイニングの難易度自動調整の仕組みを実装する

– PoWの難易度の自動調整を追加する
 L originの難易度があり、マイニングの経過した時間により難易度を上げたり下げたりする

5秒以上かかったらdifficultyを下げ、1秒以下ならdifficultyを上げる。

use serde::{Serialize, Deserialize};
use chrono::{Utc, Local, DateTime, Date};
use sha2::{Digest, Sha256};
use rand::Rng;
use std::{thread, time};
use floating_duration::TimeAsFloat;

#[derive(Debug, Serialize, Clone, Deserialize)]
struct Block {
    time: String,
    transactions: Vec<String>,
    hash: String,
    nonce: String,
}

unsafe fn pow() {
    let now = time::Instant::now();
    let previous_hash = "b9b9ee9ffc95fa4956b63b6043a99d0a8f04e0e52e687fc1958d3c6dff885f01";
    let mut num = rand::thread_rng().gen_range(0..1000000);
    let mut hash_num = format!("{}{}", previous_hash, num.to_string());
    let mut header = Sha256::digest(hash_num);
    let mut target: String  = (&hex::encode(header)[..4]).to_string();
    
    let mut cnt = 1;
    println!("count: {} {:x}", cnt, header);

    let str: String = "0".to_string();
    let difficulty_str = str.repeat(difficulty.try_into().unwrap());
    let n:usize = difficulty as usize;

    while target != difficulty_str {
        println!("count: {} {:x}", cnt, header);
        num = rand::thread_rng().gen_range(0..1000000);
        hash_num = format!("{}{}", previous_hash, num.to_string());
        header = Sha256::digest(hash_num);
        target = (&hex::encode(header)[..n]).to_string();
        cnt += 1;
    }
    println!("count: {} {:x}", cnt, header);
    println!("{:?}", now.elapsed());

    let t = vec!["sender".to_string(), "receiver".to_string(), "amount".to_string()];
    let utc_datetime: DateTime<Utc> = Utc::now();
    let b = Block{time:utc_datetime.to_string(), transactions: t, hash: hex::encode(header).to_string(), nonce:num.to_string()};
    println!("{:?}", b);
    println!("difficulty is {}", difficulty);
    if now.elapsed().as_fractional_secs() >= 5.0 {
        difficulty -= 1;
    } else if now.elapsed().as_fractional_secs() < 1.0 {
        difficulty += 1;
    }
}

static mut difficulty: u32 = 4;

fn main(){
    unsafe {pow()};       
    unsafe {pow()};   
    unsafe {pow()};        
}

$ cargo run

count: 393498 5c3b6663fe657641be5f6732ab2762fcc762aa9ffa598d6ee94dad59a4c4b9ca
count: 393499 000000215ec2fa2c01340818563a8397e50514204dcdca7f0addeeb7ff053e95
9.333024984s
Block { time: “2025-01-09 22:49:40.884851370 UTC”, transactions: [“sender”, “receiver”, “amount”], hash: “000000215ec2fa2c01340818563a8397e50514204dcdca7f0addeeb7ff053e95”, nonce: “175647” }
difficulty is 5

最初、difficultyが4だったのが、difficultyが5に変化しているのがわかります。
unsafeはあまり使いたくないですね。

【Rust】複数ファイル使用時にmain.rsのstructを利用する

main.rsで定義したstructを複数ファイル使用時にサブのrsで利用したい場合

mod sub;

#[derive(Debug)]
struct Name {
    family: String,
    first: String,
    age: i32,
}

fn main(){
    sub::print_name();
}

use crate::*;と書く。

sub.rs

use crate::Name;

pub fn print_name() {
    let n = Name { family: "Yamada".to_string(), first: "Taro".to_string(), age: 20 };
    println!("{:?}", n);
}

Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.27s
Running `target/debug/sample`
Name { family: “Yamada”, first: “Taro”, age: 20 }

なるほど〜、crateっていう表現になるのね…

【Rust】UTXOのロジックで残高照会の仕組みを実装したい

ロジック
1. blockからトランザクションデータを抽出する
2. トランザクションデータのsendに自分のアドレスがあればamountからマイナス
3. トランザクションデータのreceiverに自分のアドレスがあればamountをプラス
4. 2・3をループで回して、合計値をウォレットのGUIで表示

// gui表示
async fn handle_balance()-> axum::response::Html<String> {

    let balance = balance().unwrap();

    let tera = tera::Tera::new("templates/*").unwrap();

    let mut context = tera::Context::new();
    context.insert("title", "Index page");
    context.insert("balance", &balance);

    let output = tera.render("balance.html", &context);
    axum::response::Html(output.unwrap())
}

// balance計算
fn balance()-> Result<i32, Box<dyn std::error::Error>>{
    // アドレスの読み込み
    let contents = std::fs::read_to_string("secret.pem")
        .expect("something went wrong reading the file");
    let secret_pem = contents.trim();

    let secret_key = secret_pem.parse::<SecretKey>().unwrap();
    let private_key_serialized = hex::encode(&secret_key.to_bytes());

    let public_key = secret_key.public_key();
    let address = new_address(&public_key); 

    let mut balance: i32 = 0;
    for result in BufReader::new(File::open("blocks.txt")?).lines() {
        let l = result?;
        let param:Block = serde_json::from_str(&l).unwrap();
        for transaction in param.transactions {
            if transaction.receiver == address {
                balance += transaction.amount;
            } else if transaction.sender == address{
                balance -= transaction.amount; 
            }
        }
    }
    println!("balance is {}", balance);
    return Ok(balance);
}

うん、これは特に問題ないですね。

【Rust】ファイルの先頭行のみ読み込みたい

linesをforループで回して、1回でbreakする。。。 絶対違うように思うが、他の方法がわからん…

fn genesis_check()-> Result<(), Box<dyn std::error::Error>> {
    for result in BufReader::new(File::open("blocks.txt")?).lines() {
        let l = result?;
        let param:Block = serde_json::from_str(&l).unwrap();
        println!("{:?}", param.hash);
        break;
    }
    Ok(())
}

【Blockchain】minerがPoWした後のサーバ側の処理を考える

/chain
リクエストに対し、サーバが保持しているブロックチェーンを返すパス・変数

関数 chain_verify
マイニングを完了したマイナーから送られてきたブロックチェーンの中身をチェックして、問題なければブロックチェーンを追記する。
【処理内容】
1. first blockが改竄されていないか
2. Previous blockのハッシュ値を使用し、PoWによりハッシュ値が正しく計算されているか
3. 報酬用のトランザクションを作成する(報酬額はstaticで定義する、マイナーのアドレスが必要)
4. 生成したブロックを前のブロックに繋げて保存する

– 3.でマイナーへ報酬用のトランザクションを作成する際に、マイナーのアドレスと、大元のアドレスが必要になる。
– 本来であれば、上記1~4に加えて、merkle treeの検証も必要
– ブロックチェーンにつながっているブロックのすべてのハッシュ値を計算する場合は、計算処理が多くなりそう

【Rust】Rustでマークルツリーを作りたい

use sha2::{Digest, Sha256};

#[derive(Debug, Clone)]
enum Position {
    Right,
    Left,
}

#[derive(Debug, Clone)]
struct Node {
    left: String,
    right: String,
    parent: String,
    sibling: String,
    position: Position,
    data: String,
}

fn hash(data: String) -> String {
    let h = Sha256::digest(data.clone());
    hex::encode(h).to_string()
}

fn sha256hash(right_data: String, left_data: String) -> String {
        let s = format!("{}{}", right_data, left_data);
        let h = Sha256::digest(s);
        hex::encode(h).to_string()
}

#[derive(Debug, Clone)]
struct Tree {
    leaves: Vec<Node>,
    layer: Vec<Node>,
    root: String,
}

impl Tree {
    fn build_layer(&mut self) {
        let mut new_layer: Vec<Node> = Vec::new();

        if self.layer.len() % 2 == 1 {
            self.layer.push(self.layer[self.layer.len() - 1].clone());
        }

        for i in (0..self.layer.len()).step_by(2) {
            let parent_data = sha256hash(self.layer[i].data.clone(), self.layer[i+1].data.clone());
            let left = Node {left: "".to_string(), right: "".to_string(), parent: parent_data.clone(), sibling: self.layer[i+1].data.clone(), position: Position::Left, data: self.layer[i].data.clone()};
            let right = Node {left: "".to_string(), right: "".to_string(), parent: parent_data.clone(), sibling: self.layer[i].data.clone(), position: Position::Right, data: self.layer[i+1].data.clone()};
            let parent = Node {left: self.layer[i].data.clone(), right: self.layer[i+1].data.clone(), parent: "".to_string(), sibling: self.layer[i].data.clone(), position: Position::Left, data: parent_data.clone()};
            new_layer.push(parent.clone());
            self.leaves.push(left.clone());
            self.leaves.push(right.clone());
            self.leaves.push(parent.clone());
        }
        self.layer = new_layer;
    }

    fn build_tree(&mut self) {
        while self.layer.len() > 1 {
            let _ = self.build_layer();
        }
        self.root = self.layer[0].data.clone();
    }

    fn search(&mut self, data: String) -> Node {
        let hash_value = data.clone();
        let mut target = Node {left: "".to_string(), right: "".to_string(), parent: "".to_string(), sibling: "".to_string(), position: Position::Left, data: "".to_string()};
        for node in &self.leaves {
            if node.data == hash_value {
                let target: Node = node.clone();
            } 
        }
        return target
    }

    fn get_pass(&mut self, data: String) -> Vec<String>{
        let mut target = self.search(hash(data.clone()));
        let mut markle_pass: Vec<String> = Vec::new();
        markle_pass.push(target.data);
        while target.parent != "" {
            markle_pass.push(target.sibling);
            target = self.search(target.parent);
        }       
        return markle_pass
    }
}

fn merkle_root(v: Vec<&str>) -> String {
    let mut t = Tree {leaves: [].to_vec(), layer: [].to_vec(), root: "".to_string()};
    for n in v {
        let mut s =  Node {left: "".to_string(), right: "".to_string(), parent: "".to_string(), sibling: "".to_string(), position: Position::Left, data: hash(n.to_string())};
        t.layer.push(s.clone());
    }
    t.build_tree();
    t.root
}

fn main(){
    let v= vec!["aaa", "bbb", "ccc", "ddd", "eee", "fff", "gggg"];
    let m = merkle_root(v);
    println!("{}", m);
}

うーん….

【Rust】Rustで for i in range(0, 10, 2) をやりたい

step_by(n) が使える模様
ただし、これだと、iがイテレータになってしまうので、pythonでいう for i in range(0, 10, 2) にならない

fn main(){
    let v= vec![1, 2, 3, 4, 5, 6, 7];
    for i in v.into_iter().step_by(2) {
        println!("{}", i);
    }   
}

$ cargo run
Compiling sample v0.1.0 (/home/vagrant/dev/rust/sample)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.34s
Running `target/debug/sample`
1
3
5
7

正確にはこう↓

fn main(){
    let v= vec![1, 2, 3, 4, 5, 6, 7];
    for n in (0..v.len()).step_by(2) {
        println!("{}", v[n]);
    }   
}

Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.36s
Running `target/debug/sample`
1
3
5
7

なるほど、勉強になるね〜

【Rust】Vecへの要素の追加

appendではなく、pushを使う

fn main(){
    let mut layer: Vec<String> = vec!["hoge".to_string(), "fuga".to_string()];
    layer.push("aaa".to_string());
    println!("{:?}", layer);
}

[“hoge”, “fuga”, “aaa”]

    let mut layer: Vec<String> = vec!["hoge".to_string(), "fuga".to_string()];
    layer.push("aaa".to_string());
    println!("{:?}", layer[layer.len() - 1]);

“aaa”

これを応用して

#[derive(Debug, Clone)]
struct Tree {
    leaves: Vec<String>,
    layer: Vec<String>,
    root: String,
}

impl Tree {
    fn build_layer(&mut self) {
        let new_layer: Vec<String> = Vec::new();

        if self.layer.len() % 2 == 1 {
            self.layer.push(self.layer[self.layer.len() - 1].clone());
        }
    }
}

appendだと上手くいきませんね。

【Rust】structにenumとimplを使用したい

use sha2::{Digest, Sha256};

#[derive(Debug)]
enum Position {
    Right,
    Left,
}

#[derive(Debug)]
struct Node {
    left: String,
    right: String,
    sibling: String,
    position: Position,
    data: String,
}

impl Node {
    fn hash(&self) -> String {
        let h = Sha256::digest(self.data.clone());
        hex::encode(h).to_string()
    }
}

fn main(){
    let d = Node { left:"aaa".to_string(), right:"aaa".to_string(), sibling:"aaa".to_string(), position: Position::Left, data:"aaa".to_string()};
    println!("{:?}", d);
    println!("{:?}", d.hash());
}

Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.24s
Running `target/debug/sample`
Node { left: “aaa”, right: “aaa”, sibling: “aaa”, position: Left, data: “aaa” }
“9834876dcfb05cb167a5c24953eba58c4ac89b1adf57f28f2f9d09af107ee8f0”

これで良いのか? なんか違うような気もするが、これでmerkle treeを作っていきたい。。。