ブロックチェーンSNS概念設計:PoPアルゴリズム⑤ | 続・ティール組織 研究会のブログ

続・ティール組織 研究会のブログ

ティール組織が話題になっているが、具現化するにはどうしたらよいか?
その研究を続けるにあたり、さらに次の形態である、続・ティール組織なるものまで視野に入れ、具体的な施策・行動内容を研究・支援する会。

先までは、"愛記"についての記載で、どのようにブロックチェーンSNSに組み込んで実装していけばよいのか、概念的なところからアプローチ方法を記載していった。大まかな概念としてはひとまず終えた。次は、ブロックチェーンの概念設計といえるところまで、基本設計書に着手できるようなところまで、概念を具体化していきたい。

Proof of Place(PoP)アルゴリズム⑤

前回までをふまえて、さらに今回は、メインチェーンのプログラミングについて記載したい。

各市町村で愛の行動をしたとすると、行動した人が相手に対して愛の行動をした!というメッセージと愛の行動レベルと愛貨を渡すというトランザクションを送信する。それを各市町村の代表者たちが承認すると、メインチェーンにデータが飛んでいき、相手にも通知される。メインチェーンにてしばらくデータは保存されているが、相手が愛の行動を受信します!というボタンを押せば、受信というトランザクションとしてメインチェーンにて承認依頼となっていく。それを最終承認するのがDpoSで完全ランダム選出されたメインチェーンでの最終承認者となる。最終承認者により承認されれば、愛貨が移動するという仕組み。この際、最終承認者は、各市町村にいる必要はなく、他の世界中の市町村に居ても良い。いわゆるマイニングに相当する行為であり、世界中のマイナーが承認を行うのと同じだ。

新たな自治体のメインチェーンへの追加

各自治体が独自のブロックチェーンを持つ分散システムでは、新しい自治体を追加する際には、理想的にはメインチェーンの再プログラミングが必要ないはずである。以下は、新しい自治体の統合を処理するための高レベルなアプローチである:

・動的自治体登録:新しい自治体がメインチェーンに動的に登録できる仕組みを実装する。この登録プロセスには、自治体の基本情報の提供と初期設定が含まれる。

・スマートコントラクトによる相互作用:メインチェーンと自治体のブロックチェーン間の相互作用を管理するためにスマートコントラクトを使用する。これらのコントラクトは、新しい自治体を手動で介入することなく柔軟に対応できるようにする必要がある。

・標準化されたインターフェイス:メインチェーンと自治体のブロックチェーン間の通信のための標準化されたインターフェイスを定義する。これにより、新しい自治体がこれらのインターフェースに準拠することで容易に統合できるようになる。

・コンセンサスメカニズム:DPoSなど、動的参加をサポートするコンセンサスメカニズムを使用する。これにより、新しい自治体が大規模な再構成なしにコンセンサスプロセスに参加できるようになる。

・スケーラブルなアーキテクチャ:新しい自治体を追加してもメインチェーンのパフォーマンスに大きな影響を与えないように、システムをスケーラブルに設計する。

・テストとシミュレーション:新しい自治体を本番システムに追加する前に、互換性を確認し、潜在的な問題を特定するために、十分なテストとシミュレーションを実施する。

・コミュニティガバナンス:既存の自治体が新しい自治体の統合を承認できるようにするガバナンスモデルを確立する。これにより、すべての参加者の利益が考慮されることが保証される。

 

これらの原則に従うことで、新しい自治体を追加する際にメインチェーンの再プログラミングが不要で、統合がシームレスに行われるシステムを作成できる。

 

この具体例を実現するために、AさんとBさんがそれぞれの市町村で愛貨を申請し、保有している状態を模擬するために、以下の手順でメインチェーンのプログラムをやってみよう。なお、Aさんは石川県加賀市の住民、Bさんは石川県金沢市の住民であるとする。

  1. Aさんが横浜市内で愛の行動を行い、PoPで位置と時間の証明を行い、愛貨を送信するトランザクションを生成する。
  2. 生成したトランザクションはAさん所属の石川県加賀市のブロックチェーンに追加され、代表者に承認される。
  3. Bさんが時間差で大阪市内で愛の行動を受け取り、PoPで位置と時間の証明を行い、愛貨を受け取るトランザクションを生成する。
  4. 生成したトランザクションはBさん所属の石川県金沢市のブロックチェーンに追加される。
  5. Bさんが受け取りボタンを押すことで、愛貨の受け取りがメインチェーンにリクエストされる。
  6. メインチェーンで受け取りがDPosでランダム選出された最終承認者により承認され、AさんからBさんへと愛貨が移動する。
以下は、愛貨の移動を含むシナリオをシミュレートするRustのコードである。このコードは、Aさんが横浜市で愛の行動を行い、Bさんが大阪市でその行動を受け取る場合のプロセスを示している。このシナリオでは、AさんとBさんがそれぞれ石川県の市町村に参加しており、愛の行動の承認はDPoSによって行われる。また、Aさんが愛貨を送信し、Bさんが受け取りボタンを押すことで愛貨の移動が完了する。
 
use sha2::{Digest, Sha256};
use chrono::{DateTime, Utc};
use std::collections::HashMap;
use std::time::Duration;

#[derive(Debug)]
struct Transaction {
    transaction_id: String,
    municipality: String,
    timestamp: DateTime<Utc>,
    location: String,
    love_action_level: u32,
    amount: f64,
    action_content: String,
    is_local: bool,
    close_flag: bool,
    approval_target: Option<String>,
    signature: Option<String>,
    location_hash: Vec<u8>,
    received_timestamp: Option<DateTime<Utc>>,
}

impl Transaction {
    fn calculate_location_hash(&mut self) {
        let mut hasher = Sha256::new();
        hasher.update(self.location.clone());
        self.location_hash = hasher.finalize().to_vec();
    }

    fn generate_signature(&mut self) {
        let message = format!(
            "{}{}{}{}{}{}{}{}",
            self.transaction_id,
            self.municipality,
            self.timestamp.to_rfc3339(),
            self.location,
            self.love_action_level,
            self.amount,
            self.action_content,
            String::from_utf8_lossy(&self.location_hash)
        );
        self.signature = Some(sha2::Sha256::digest(message.as_bytes()).to_string());
    }

    fn receive_love_currency(&mut self) -> f64 {
        if self.received_timestamp.is_none() {
            self.received_timestamp = Some(Utc::now());
        }
        let time_diff = Utc::now() - self.received_timestamp.unwrap();
        let hours_diff = time_diff.num_hours() as f64;
        let decreased_amount = self.amount - (hours_diff * 0.05); // 1時間ごとに5%ずつ減少
        self.amount = decreased_amount.max(0.0); // 愛貨が0未満にならないようにする
        self.amount
    }
}

#[derive(Debug)]
struct Approver {
    name: String,
    is_selected: bool,
}

impl Approver {
    fn select_approver(approvers: &mut HashMap<String, Approver>) -> Option<String> {
        let mut selected_approver: Option<String> = None;
        for (name, approver) in approvers.iter_mut() {
            if !approver.is_selected {
                approver.is_selected = true;
                selected_approver = Some(name.clone());
                break;
            }
        }
        selected_approver
    }
}

fn main() {
    let mut transaction_a = Transaction {
        transaction_id: "123456".to_string(),
        municipality: "Kaga".to_string(),
        timestamp: Utc::now(),
        location: "35.4436, 139.6372".to_string(), // 横浜市
        love_action_level: 3,
        amount: 100.0,
        action_content: "Helped someone carry groceries".to_string(),
        is_local: false,
        close_flag: false,
        approval_target: None,
        signature: None,
        location_hash: Vec::new(),
        received_timestamp: None,
    };

    transaction_a.calculate_location_hash();
    transaction_a.generate_signature();

    let mut transaction_b = Transaction {
        transaction_id: "654321".to_string(),
        municipality: "Kanazawa".to_string(),
        timestamp: Utc::now() + Duration::hours(1),
        location: "34.6937, 135.5023".to_string(), // 大阪市
        love_action_level: 3,
        amount: 0.0,
        action_content: "Received help carrying groceries".to_string(),
        is_local: false,
        close_flag: false,
        approval_target: None,
        signature: None,
        location_hash: Vec::new(),
        received_timestamp: None,
    };

    transaction_b.calculate_location_hash();
    transaction_b.generate_signature();

    let mut approvers: HashMap<String, Approver> = HashMap::new();
    approvers.insert("Approver1".to_string(), Approver { name: "Approver1".to_string(), is_selected: false });
    approvers.insert("Approver2".to_string(), Approver { name: "Approver2".to_string(), is_selected: false });

    if let Some(approver_name) = Approver::select_approver(&mut approvers) {
        transaction_a.approval_target = Some(approver_name.clone());
        println!("Transaction A approved by {}", approver_name);
    }

    if let Some(approver_name) = Approver::select_approver(&mut approvers) {
        transaction_b.approval_target = Some(approver_name.clone());
        println!("Transaction B approved by {}", approver_name);
    }

    transaction_b.amount = transaction_b.receive_love_currency();

    println!("Transaction A: {:?}", transaction_a);
    println!("Transaction B: {:?}", transaction_b);
}
 
上記のコードは、新しい自治体を追加する際にメインチェーンの再プログラミングが不要で、シームレスに統合できるように設計されている。
 

各ブロックチェーンとメインチェーンをつなぐAPI

APIの設計例として、愛貨システムのトランザクション管理に関する基本的な機能を提供するAPIを考えてみよう。独自のAPIを開発する場合、以下のような仮説を立ててみることができる。
  1. APIの設計: 独自のプロトコルに基づいたAPIを設計する必要がある。このAPIは、メインチェーンと各自治体のブロックチェーン間の通信を管理し、新しい自治体をシームレスに統合できるようにする必要がある。

  2. 通信プロトコル: メインチェーンと自治体のブロックチェーン間の通信に使用するプロトコルを決定する必要がある。これには、データの送受信、承認プロセス、エラーハンドリングなどが含まれる。

  3. データ形式: APIが使用するデータ形式を定義する必要がある。これには、トランザクションデータ、承認依頼、承認結果などが含まれる。

  4. 認証とセキュリティ: APIには認証機能を実装し、セキュリティを確保する必要がある。これには、データの暗号化、アクセス制御などが含まれる。

  5. テストとシミュレーション: APIを開発する前に、十分なテストとシミュレーションを行うことが重要である。これにより、システムが正常に動作し、新しい自治体の統合がスムーズに行われることが確認される。

これらの仮説をもとに、独自のAPIを開発するためのプロトタイプを作成してみることができる。以下は、トランザクションの作成、承認者の選択、承認プロセスの進行などの機能を持つAPIの設計例である。

use sha2::{Digest, Sha256};
use chrono::{DateTime, Utc};
use std::collections::HashMap;

// トランザクションの構造体
#[derive(Debug)]
pub struct Transaction {
    pub transaction_id: String,
    pub municipality: String,
    pub timestamp: DateTime<Utc>,
    pub location: String,
    pub love_action_level: u32,
    pub amount: f64,
    pub action_content: String,
    pub is_local: bool,
    pub close_flag: bool,
    pub approval_target: Option<String>,
    pub signature: Option<String>,
    pub location_hash: Vec<u8>,
    pub received_timestamp: Option<DateTime<Utc>>,
}

impl Transaction {
    pub fn new(
        transaction_id: &str,
        municipality: &str,
        location: &str,
        love_action_level: u32,
        amount: f64,
        action_content: &str,
    ) -> Self {
        let timestamp = Utc::now();
        let mut hasher = Sha256::new();
        hasher.update(location);
        let location_hash = hasher.finalize().to_vec();

        Transaction {
            transaction_id: transaction_id.to_string(),
            municipality: municipality.to_string(),
            timestamp,
            location: location.to_string(),
            love_action_level,
            amount,
            action_content: action_content.to_string(),
            is_local: false,
            close_flag: false,
            approval_target: None,
            signature: None,
            location_hash,
            received_timestamp: None,
        }
    }

    pub fn calculate_location_hash(&mut self) {
        let mut hasher = Sha256::new();
        hasher.update(self.location.clone());
        self.location_hash = hasher.finalize().to_vec();
    }

    pub fn generate_signature(&mut self) {
        let message = format!(
            "{}{}{}{}{}{}{}{}",
            self.transaction_id,
            self.municipality,
            self.timestamp.to_rfc3339(),
            self.location,
            self.love_action_level,
            self.amount,
            self.action_content,
            String::from_utf8_lossy(&self.location_hash)
        );
        self.signature = Some(sha2::Sha256::digest(message.as_bytes()).to_string());
    }

    pub fn receive_love_currency(&mut self) -> f64 {
        if self.received_timestamp.is_none() {
            self.received_timestamp = Some(Utc::now());
        }
        let time_diff = Utc::now() - self.received_timestamp.unwrap();
        let hours_diff = time_diff.num_hours() as f64;
        let decreased_amount = self.amount - (hours_diff * 0.05); // 1時間ごとに5%ずつ減少
        self.amount = decreased_amount.max(0.0); // 愛貨が0未満にならないようにする
        self.amount
    }
}

// 承認者の構造体
#[derive(Debug)]
pub struct Approver {
    pub name: String,
    pub is_selected: bool,
}

impl Approver {
    pub fn new(name: &str) -> Self {
        Approver {
            name: name.to_string(),
            is_selected: false,
        }
    }

    pub fn select_approver(approvers: &mut HashMap<String, Approver>) -> Option<String> {
        let mut selected_approver: Option<String> = None;
        for (name, approver) in approvers.iter_mut() {
            if !approver.is_selected {
                approver.is_selected = true;
                selected_approver = Some(name.clone());
                break;
            }
        }
        selected_approver
    }
}

このAPI設計例はシステム全体の管理や拡張性を考慮した設計を行っており、具体的な機能や操作を行うための実装を提供している。さらなる詳細な機能も実際に合わせて加えていく必要はあるのだろうが。
 
 
では、先のメインチェーンのプログラムに、上記の愛貨システムのAPIを実装してみよう。以下は、APIの実装例である。
use sha2::{Digest, Sha256};
use chrono::{DateTime, Utc};
use std::collections::HashMap;
use std::time::Duration;

// トランザクションの構造体
#[derive(Debug)]
struct Transaction {
    transaction_id: String,
    municipality: String,
    timestamp: DateTime<Utc>,
    location: String,
    love_action_level: u32,
    amount: f64,
    action_content: String,
    is_local: bool,
    close_flag: bool,
    approval_target: Option<String>,
    signature: Option<String>,
    location_hash: Vec<u8>,
    received_timestamp: Option<DateTime<Utc>>,
}

impl Transaction {
    fn calculate_location_hash(&mut self) {
        let mut hasher = Sha256::new();
        hasher.update(self.location.clone());
        self.location_hash = hasher.finalize().to_vec();
    }

    fn generate_signature(&mut self) {
        let message = format!(
            "{}{}{}{}{}{}{}{}",
            self.transaction_id,
            self.municipality,
            self.timestamp.to_rfc3339(),
            self.location,
            self.love_action_level,
            self.amount,
            self.action_content,
            String::from_utf8_lossy(&self.location_hash)
        );
        self.signature = Some(sha2::Sha256::digest(message.as_bytes()).to_string());
    }

    fn receive_love_currency(&mut self) -> f64 {
        if self.received_timestamp.is_none() {
            self.received_timestamp = Some(Utc::now());
        }
        let time_diff = Utc::now() - self.received_timestamp.unwrap();
        let hours_diff = time_diff.num_hours() as f64;
        let decreased_amount = self.amount - (hours_diff * 0.05); // 1時間ごとに5%ずつ減少
        self.amount = decreased_amount.max(0.0); // 愛貨が0未満にならないようにする
        self.amount
    }

    // 新たに追加したメソッド
    fn verify_signature(&self) -> bool {
        if let Some(signature) = &self.signature {
            let message = format!(
                "{}{}{}{}{}{}{}{}",
                self.transaction_id,
                self.municipality,
                self.timestamp.to_rfc3339(),
                self.location,
                self.love_action_level,
                self.amount,
                self.action_content,
                String::from_utf8_lossy(&self.location_hash)
            );
            let calculated_signature = sha2::Sha256::digest(message.as_bytes()).to_string();
            return *signature == calculated_signature;
        }
        false
    }
}

// 承認者の構造体
#[derive(Debug)]
struct Approver {
    name: String,
    is_selected: bool,
}

impl Approver {
    fn select_approver(approvers: &mut HashMap<String, Approver>) -> Option<String> {
        let mut selected_approver: Option<String> = None;
        for (name, approver) in approvers.iter_mut() {
            if !approver.is_selected {
                approver.is_selected = true;
                selected_approver = Some(name.clone());
                break;
            }
        }
        selected_approver
    }
}

// APIの実装
struct LoveCurrencyApi;

impl LoveCurrencyApi {
    // メインチェーンから自治体のブロックチェーンにデータを送信するメソッド
    fn send_data_to_municipality_chain(transaction: &Transaction, municipality: &str) {
        if transaction.verify_signature() {
            println!("Sending data to municipality chain: {:?}", transaction);
            // メインチェーンから自治体のブロックチェーンにデータを送信する処理を実装する
        } else {
            println!("Failed to send data: Invalid signature");
        }
    }

    // 新しい自治体を登録するメソッド
    fn register_new_municipality(municipality_name: &str) {
        println!("Registering new municipality: {}", municipality_name);
        // 新しい自治体を登録する処理を実装する
    }

    // APIの初期化処理
    fn init() -> Self {
        LoveCurrencyApi
    }
}

fn main() {
    let mut transaction_a = Transaction {
        transaction_id: "123456".to_string(),
        municipality: "Kaga".to_string(),
        timestamp: Utc::now(),
        location: "35.4436, 139.6372".to_string(), // 横浜市
        love_action_level: 3,
        amount: 100.0,
        action_content: "Helped someone carry groceries".to_string(),
        is_local: false,
        close_flag: false,
        approval_target: None,
        signature: None,
        location_hash: Vec::new(),
        received_timestamp: None,
    };

    transaction_a.calculate_location_hash();
    transaction_a.generate_signature();

    let mut transaction_b = Transaction {
        transaction_id: "654321".to_string(),
        municipality: "Kanazawa".to_string(),
        timestamp: Utc::now() + Duration::hours(1),
        location: "34.6937, 135.5023".to_string(), // 大阪市
        love_action_level: 3,
        amount: 0.0,
        action_content: "Received help carrying groceries".to_string(),
        is_local: false,
        close_flag: false,
        approval_target: None,
        signature: None,
        location_hash: Vec::new(),
        received_timestamp: None,
    };

    transaction_b.calculate_location_hash();
    transaction_b.generate_signature();

    let mut approvers: HashMap<String, Approver> = HashMap::new();
    approvers.insert("Approver1".to_string(), Approver { name: "Approver1".to_string(), is_selected: false });
    approvers.insert("Approver2".to_string(), Approver { name: "Approver2".to_string(), is_selected: false });

    if let Some(approver_name) = Approver::select_approver(&mut approvers) {
        transaction_a.approval_target = Some(approver_name.clone());
        println!("Transaction A approved by {}", approver_name);
    }

    if let Some(approver_name) = Approver::select_approver(&mut approvers) {
        transaction_b.approval_target = Some(approver_name.clone());
        println!("Transaction B approved by {}", approver_name);
    }

    transaction_b.amount = transaction_b.receive_love_currency();

    println!("Transaction A: {:?}", transaction_a);
    println!("Transaction B: {:?}", transaction_b);

    // APIを初期化
    let api = LoveCurrencyApi::init();

    // 新しい自治体を登録する例
    api.register_new_municipality("Saitama");

    // メインチェーンから自治体のブロックチェーンにデータを送信する例
    api.send_data_to_municipality_chain(&transaction_a, "Saitama");
}
 
この例では、LoveCurrencyApiというAPIを追加し、メインチェーンの処理に関連付けている。LoveCurrencyApiでは、メインチェーンから自治体のブロックチェーンにデータを送信するsend_data_to_municipality_chainメソッドと、新しい自治体を登録するregister_new_municipalityメソッドを実装している。これにより、API経由で愛貨システムの様々な操作を行うことができる。
 
 
いかがであろうか、メインチェーンのプログラミングもやってみた。各市町村のブロックチェーンとメインチェーンが独自のAPIを通じフェデレーションモデルで繋がっている。これを実現させていくにはまだ様々な設計が必要であるのだが。