愛記システムの基本設計:DApps側である愛記システム 要件定義について⑨ | 続・ティール組織 研究会のブログ

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

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

先までは、"愛記"についての記載で、どのようにブロックチェーンSNSに組み込んで実装していけばよいのか、概念的なところからアプローチ方法を記載していった。概念設計としてはひとまず終えた。次は、フェデレーションモデル全体の基本設計といえるところまで、基本設計書に着手できるようなところまで、概念を具体化していきたい。そして、それにつながるDApps側である「愛記システム」を、Pythonプログラムで開発していきたい。

 

愛の行動のPL,BSを決算書として、個人単位、市町村単位、で公表するような愛記システムというものを考えている。愛の行動のデータベースはブロックチェーンのプログラムであり、日々の愛の行動による愛貨の移動を決算書にまとめていきたい。なお、市町村のブロックチェーンのプログラムは以前にも記載している。その市町村のブロックチェーンのプログラムにつながる愛記システムを、DApps側であるPythonプログラムとして設計したい。その場合、基本設計をどのような手順で進めていけばよいか、詳しく見ていこう。

 

愛記システムを設計するための基本手順を以下に示す。このシステムは、Pythonを用いて市町村のブロックチェーンと連携し、個人および市町村単位での愛の行動のデータを収集、記録し、決算書(PL、BS)として公表するものである。

基本設計のステップ

  1. 要件定義
  2. アーキテクチャ設計
  3. データベース設計
  4. API設計
  5. ブロックチェーンインターフェース
  6. 決算書の生成
  7. フロントエンド開発
  8. テストとデプロイ

基本設計の各ステップを順番に進めることで、ブロックチェーンとDAppsとして繋がる「愛記システム」の詳細な設計が可能になる。各ステップでは、関係者との協議やレビューを通じて設計内容を確定していくことが重要である。

1.要件定義

まず、基本設計の最初のステップである要件定義をしていきたい。どのような機能が必要か、どのような問題を解決するのかを洗い出したい。要件定義はシステム設計の最初の重要なステップであり、システムが解決するべき問題と、必要な機能を明確に定義するプロセスである。以下に、愛記システムのプログラムに必要な機能と解決すべき問題を列挙してみよう。

機能要件

  1. 愛の行動の記録

  2. 愛貨の移動の記録

  3. 決算書の生成

  4. 個人および市町村単位でのデータの集約

  5. データのブロックチェーンへの記録と取得

  6. 愛貨の管理

  7. ユーザー管理

  8. 通知機能

  9. レポート機能

  10. ダッシュボード

非機能要件

  1. セキュリティ

  2. 可用性

  3. パフォーマンス

  4. スケーラビリティ

  5. ユーザビリティ

  6. コンプライアンス

解決すべき問題

  1. 透明性と信頼性の確保

  2. データの一元管理

  3. 愛の行動の促進

  4. 評価制度の確立

  5. データのセキュリティとプライバシーの保護

これらの要件を基に、愛記システムの基本設計を進めていくことが重要である。次のステップでは、これらの要件を具体的なアーキテクチャ設計に反映していくことになる。まずは、要件定義の解決すべき問題を一つずつクリアにしていきたい。

透明性と信頼性の確保

愛貨の取引と愛の行動の記録を透明にし、信頼性を確保することが重要だ。以下に、具体的な項目とその決定プロセスを記載する。

・透明性と信頼性の確保に必要な項目と決定プロセス

1. データの完全性と一貫性の保証

  • データの完全性: すべての取引と愛の行動記録が正確かつ改ざんされていないことを保証する。
    ・取引ID (Transaction ID)
    ・日時 (Timestamp)
    ・送信者 (Sender)
    ・受信者 (Receiver)
    ・愛貨の量 (Amount of Love Tokens)
    ・取引の内容 (Transaction Content)
    ・署名 (Signature)
    ・ハッシュ値 (Hash Value)
    ・取引ステータス (Transaction Status)
    ・取引のカテゴリ (Transaction Category)
    ・証拠データ (Proof Data)
    ・受信日時 (Received Timestamp)
    ・ジオロケーションデータ (Geolocation Data)
    ・関連取引ID (Related Transaction ID)
    ・メタデータ (Metadata)
    ・ゼロ知識証明 (Zero-Knowledge Proof)
    ・承認者情報 (Approver Information)
    ・取引費用 (Transaction Fee)
    ・関連アクションID (Related Action ID)
    ・愛の行動レベル (Love Action Level)
    取引データの完全性を保証するための詳細な項目は上記のような20項目すべてを基本設計に盛り込んで行く。
     

  • データの一貫性: システム全体でデータが統一されていることを確認する。

2. 取引の透明性の確保

  • 公開取引データ: 取引データを公開し、誰でも確認できるようにする。

  • 監査ログ: 取引や行動のすべての変更履歴を保持し、監査可能にする。

3. データのセキュリティとプライバシー保護

  • 暗号化: データの送受信時および保存時に暗号化を行い、データの安全性を確保。

  • アクセス制御: データへのアクセスを制御し、必要な権限を持つユーザーのみに限定。

4. 取引の正当性の確認

  • 署名の生成と検証: 取引データの署名を生成し、取引の正当性を検証。

  • 取引の検証: 各取引を検証し、不正行為や二重支出を防止。

これらの項目を詳細に決定し、実装することで、愛記システムの透明性と信頼性を確保することができる。各項目については、具体的な技術要件や設計仕様を定義し、システム開発の各フェーズで反映させることが重要である。


・データの一貫性について

データの完全性と一貫性を確保するための基本設計とプログラムの例を以下に示す。具体的にどのような項目を設計し、どのように実装するかについて詳しく説明する。

基本設計

1. データの一貫性

システム全体でデータが統一されていることを確認するために、次の点に注意する。

  • トランザクションのアトミック性: トランザクションが完全に成功するか、まったく成功しないかを保証する。
  • データの整合性チェック: データが一貫性を保つための整合性チェックを設計する。
  • データの同期: 分散システム間でデータの同期を適切に行う。

2. データの完全性

データが損なわれないようにするために、次の点に注意します。

  • データの暗号化: データの機密性を確保するために、保存時および通信時にデータを暗号化する。
  • データのバリデーション: 入力データをバリデーションして、不正なデータがシステムに入らないようにする。

3. 監査ログ

すべての操作を監査ログに記録し、後から検証可能にする。

プログラム例

以下に、データの完全性と一貫性を確保するための具体的なプログラム例を示す。


1. トランザクションのアトミック性

トランザクションのアトミック性を確保するために、データベースのトランザクション機能を使用する。
import sqlite3

def execute_transaction(queries):
    conn = sqlite3.connect('example.db')
    try:
        conn.execute('BEGIN')
        for query in queries:
            conn.execute(query)
        conn.commit()
    except Exception as e:
        conn.rollback()
        print(f"Transaction failed: {e}")
    finally:
        conn.close()

queries = [
    "INSERT INTO users (id, name) VALUES (1, 'Alice')",
    "INSERT INTO accounts (user_id, balance) VALUES (1, 1000)"
]

execute_transaction(queries)
 

2. データの整合性チェック

データの整合性をチェックする関数を設計する。
def check_data_integrity(data):
    # 例として、ユーザーIDが正の整数であることを確認
    if 'user_id' in data and isinstance(data['user_id'], int) and data['user_id'] > 0:
        return True
    return False

data = {'user_id': 1, 'balance': 1000}
if check_data_integrity(data):
    print("Data is valid")
else:
    print("Data integrity check failed")
 

3. データの暗号化

データを暗号化して保存する。
from cryptography.fernet import Fernet

# 秘密鍵の生成
key = Fernet.generate_key()
cipher_suite = Fernet(key)

# データの暗号化
data = b"Sensitive data"
cipher_text = cipher_suite.encrypt(data)

# データの復号化
plain_text = cipher_suite.decrypt(cipher_text)
print(plain_text)
 

4. 監査ログ

すべての操作を監査ログに記録する。
import logging

# ログ設定
logging.basicConfig(filename='audit.log', level=logging.INFO, format='%(asctime)s - %(message)s')

def log_action(action, data):
    logging.info(f"Action: {action}, Data: {data}")

# 例: ユーザーの作成をログに記録
log_action("Create User", {"user_id": 1, "name": "Alice"})

まとめ

データの完全性と一貫性を確保するためには、トランザクションのアトミック性、データの整合性チェック、データの暗号化、監査ログの記録が重要である。これらの設計を適切に行うことで、システム全体でのデータの一貫性を保証し、信頼性の高いシステムを構築できる。

 

 

では、以下にトランザクションのアトミック性から順番に見ていくことにする。

・トランザクションのアトミック性:

設計ポイント
・二相コミットプロトコル(2PC): 分散トランザクションを確実に完了させるためのプロトコル。 

・トランザクション管理システム: 各ノードがトランザクションの状態を管理し、一貫性を保証。 
 

フェデレーションモデルにおいて、何百万人ものユーザーが参加する場合でも、トランザクションのアトミック性を確保するために、二相コミットプロトコル(2PC)を使用して分散トランザクションを確実に完了させることが重要である。以下に、二相コミットプロトコルの概念とフェデレーションモデルでの適用方法について詳しく説明する。

二相コミットプロトコル(2PC)の概念

二相コミットプロトコル(2PC)は、分散システムにおいてトランザクションをアトミックに実行するためのプロトコルである。2PCは次の2つのフェーズで構成されている。

  1. 準備フェーズ(Prepare Phase):

    • コーディネータがすべての参加者(ノード)に対して「準備できたかどうか」を問い合わせる。
    • すべての参加者がトランザクションをローカルに適用し、コミット可能な状態かどうかを判断し、結果をコーディネータに返す。
  2. コミットフェーズ(Commit Phase):

    • コーディネータがすべての参加者から「準備完了」の応答を受け取った場合、コミットを実行するよう指示する。
    • コーディネータがいずれかの参加者から「準備できない」応答を受け取った場合、ロールバックを指示する。

フェデレーションモデルでの適用方法

フェデレーションモデルにおける二相コミットプロトコルの適用は、以下のステップで行う。

  1. トランザクション生成と初期承認:

    • DApps側でトランザクションを生成し、市町村のブロックチェーンに送信する。
    • 市町村のブロックチェーンで初期承認を行い、トランザクションをペンディング状態にする。
  2. 準備フェーズ(Prepare Phase):

    • 市町村のブロックチェーンがトランザクションをメインチェーンに送信し、すべての関係するノードに対して「準備完了」の確認を行う。
    • 各ノードがトランザクションをローカルに適用し、コミット可能な状態かどうかを判断する。
  3. コミットフェーズ(Commit Phase):

    • メインチェーンがすべてのノードから「準備完了」の応答を受け取った場合、コミットを指示する。
    • いずれかのノードが「準備できない」場合、ロールバックを指示する。

実装例

以下に、フェデレーションモデルでの二相コミットプロトコルをシミュレートするコード例を示す。

1. トランザクション生成と初期承認(Python, DApps側)
import requests
import json

def create_transaction(sender, receiver, amount, location):
    transaction = {
        "sender": sender,
        "receiver": receiver,
        "amount": amount,
        "location": location,
        "timestamp": str(datetime.now())
    }
    response = requests.post("http://localhost:8080/transactions", json=transaction)
    return response.json()

transaction = create_transaction("user1", "user2", 100, "35.6895, 139.6917")
print(transaction)
 

2. 市町村のブロックチェーン(Rust)
use actix_web::{post, web, App, HttpResponse, HttpServer, Responder};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::sync::{Arc, Mutex};

#[derive(Debug, Clone, Serialize, Deserialize)]
struct Transaction {
    sender: String,
    receiver: String,
    amount: f64,
    location: String,
    timestamp: String,
    status: String,
}

struct AppState {
    transactions: Mutex<HashMap<String, Transaction>>,
}

#[post("/transactions")]
async fn receive_transaction(data: web::Data<AppState>, req: web::Json<Transaction>) -> impl Responder {
    let mut transactions = data.transactions.lock().unwrap();
    let transaction = req.into_inner();
    transactions.insert(transaction.timestamp.clone(), transaction.clone());
    HttpResponse::Ok().json(transaction)
}

#[post("/prepare")]
async fn prepare_transaction(data: web::Data<AppState>, req: web::Json<String>) -> impl Responder {
    let transaction_id = req.into_inner();
    let mut transactions = data.transactions.lock().unwrap();

    if let Some(transaction) = transactions.get_mut(&transaction_id) {
        transaction.status = "Prepared".to_string();
        HttpResponse::Ok().json("Prepared")
    } else {
        HttpResponse::BadRequest().json("Transaction not found")
    }
}

#[post("/commit")]
async fn commit_transaction(data: web::Data<AppState>, req: web::Json<String>) -> impl Responder {
    let transaction_id = req.into_inner();
    let mut transactions = data.transactions.lock().unwrap();

    if let Some(transaction) = transactions.get_mut(&transaction_id) {
        transaction.status = "Committed".to_string();
        HttpResponse::Ok().json("Committed")
    } else {
        HttpResponse::BadRequest().json("Transaction not found")
    }
}

#[post("/rollback")]
async fn rollback_transaction(data: web::Data<AppState>, req: web::Json<String>) -> impl Responder {
    let transaction_id = req.into_inner();
    let mut transactions = data.transactions.lock().unwrap();

    if let Some(transaction) = transactions.remove(&transaction_id) {
        HttpResponse::Ok().json("Rolled back")
    } else {
        HttpResponse::BadRequest().json("Transaction not found")
    }
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    let app_state = web::Data::new(AppState {
        transactions: Mutex::new(HashMap::new()),
    });

    HttpServer::new(move || {
        App::new()
            .app_data(app_state.clone())
            .service(receive_transaction)
            .service(prepare_transaction)
            .service(commit_transaction)
            .service(rollback_transaction)
    })
    .bind("0.0.0.0:8080")?
    .run()
    .await
}
 

この例では、市町村のブロックチェーンがトランザクションを受信し、準備フェーズおよびコミットフェーズを実装している。各フェーズでトランザクションの状態を変更し、二相コミットプロトコルに基づいて処理する。

メリットとデメリット

メリット

  • 一貫性の保証: トランザクションがアトミックに実行されるため、データの一貫性が保証される。
  • 透明性: すべてのトランザクションがフェデレーションモデルで管理され、透明性が向上する。

デメリット

  • 複雑性の増加: 二相コミットプロトコルの実装は複雑であり、エラー処理やタイムアウトの管理が必要。
  • パフォーマンスの影響: すべてのノードとの通信が必要であり、ネットワーク遅延やオーバーヘッドが発生する可能性がある。

結論

フェデレーションモデルにおいて、トランザクションのアトミック性を確保するためには、二相コミットプロトコル(2PC)を使用することが有効である。このプロトコルを適用することで、分散システム全体でデータの完全性と一貫性を保証できる。トランザクションの生成と承認を適切に管理し、フェデレーションモデルの信頼性と透明性を向上させることができる。
 

 

いかがであろうか、上記の例はシンプルなものだが、次回以降、実際のシステムではこれらの基本概念を組み合わせて複雑なデータ管理を行うため、特に分散システムでは、データの同期やネットワークの遅延なども考慮に入れる必要があるため、一つずつ詳細を見ていく。