先までは、"愛記"についての記載で、どのようにブロックチェーンSNSに組み込んで実装していけばよいのか、概念的なところからアプローチ方法を記載していった。概念設計としてはひとまず終えた。次は、フェデレーションモデル全体の基本設計といえるところまで、基本設計書に着手できるようなところまで、概念を具体化していきたい。
フェデレーションモデルのブロックチェーンの基本設計を進めるには、以下の手順に従って詳細に設計していくことが重要である。これにはシステムの機能、アーキテクチャ、データフロー、技術スタック、および具体的な実装方法の設計が含まれる。
基本設計のステップ
-
要求分析
-
システムアーキテクチャの設計
-
データフローの設計
-
技術スタックの選定
-
データモデルの設計
-
API設計
-
セキュリティ設計
-
エラーハンドリングとログ設計
基本設計の各ステップを順番に進めることで、フェデレーションモデルのブロックチェーンの詳細な設計が可能になる。各ステップでは、関係者との協議やレビューを通じて設計内容を確定していくことが重要である。
1.要求分析
まず、基本設計の最初のステップである要求分析をしていきたい。どのような機能が必要か、どのような問題を解決するのかを洗い出したい。要求分析はシステム設計の最初の重要なステップであり、システムが解決するべき問題と、必要な機能を明確に定義するプロセスである。以下に、メインチェーンとフェデレーションモデルでつながる市町村のブロックチェーンのプログラムに必要な機能と解決すべき問題を列挙してみよう。
解決すべき問題
-
データの一貫性と整合性
-
スケーラビリティとパフォーマンス
-
ガバナンスとコンセンサス
-
システムの拡張性
-
トランザクションの信頼性とセキュリティ
-
トランザクションのトレーサビリティ
必要な機能
-
トランザクション生成
-
トランザクションの検証
-
トランザクション承認と統合
-
ブロック生成
-
自治体の登録と管理
-
履歴証明(Proof of History)
-
APIゲートウェイ
-
ガバナンス機能
-
セキュリティ機能
-
スケーラビリティとパフォーマンス最適化
コンセンサスの設計項目
-
コンセンサスアルゴリズムの選定
- DPoS (Delegated Proof of Stake): 市町村代表がトランザクションを承認するためのアルゴリズム。
- PoP(Proof of Place): 位置証明。各ノードや承認の位置を証明することで、地域間の利益を演出するためのアルゴリズム。
- PoH (Proof of History): 履歴証明。トランザクションの順序を保証するためのアルゴリズム。
-
代表選出のメカニズム
- 選出プロセス: 代表ノードを選ぶためのプロセス(例: 投票、ランダム選出)。
- 任期と再選ルール: 代表ノードの任期や再選ルールを設定。
-
コンセンサスの合意形成
- 合意形成のフロー: トランザクションがどのように承認されるか(例: 提案→検証→承認)。
- コンフリクト解決メカニズム: コンフリクトが発生した場合の解決方法(例: 再投票、仲裁)。
-
コンセンサスの拡張性と効率化
- スケーラブルな合意形成: ノード数が増えてもコンセンサスを効率的に行うための手法。
- APIゲートウェイ: 効率的でセキュリティも強化されたAPIが必要。
- 最適化戦略: コンセンサスプロセスを最適化するための技術的手法(例: 先行承認、PoP活用)。
合意形成のフロー
これまでの内容をもとに、Municipal_ChainとContinental_Main_Chainの設計を行う。今回は各フェーズごとに具体的なデータフローとロジックを丁寧に解説したい。
1. Municipal Chainの設計
Municipal Chainは、各市町村ごとに存在し、住民が提案するトランザクションを受け付け、それを承認する役割を持つ。トランザクションが承認されると、Continental_Main_Chainに送信される。
1.1 トランザクション提案フェーズ
誰が: トランザクションの送信者(市町村内の住民)
何を: トランザクションを提案し、Municipal Chainに送信
いつ: トランザクションが生成されたとき
どのように:
- DAppsでのトランザクション生成: 住民がDApps(デジタルアプリケーション)を使用してトランザクションを作成する。このトランザクションには、送信者、受信者、金額、トランザクションの詳細情報(例: PoP証明、アクションレベル、ディメンションなど)が含まれる。
- Municipal_Chainへのトランザクション送信: DAppsは生成されたトランザクションをMunicipal_Chainに送信する。
1.2 トランザクション検証フェーズ
誰が: Municipal_Chainの代表者(DPoSにより選出)
何を: トランザクションの内容と送信者のPoP証明を検証
いつ: トランザクションがMunicipal_Chainに送信された後
どのように:
- DPoSによる代表者の選出: Municipal_Chainは、DPoS(Delegated Proof of Stake)を使用して代表者を選出する。選ばれた3人の代表者のうち1人がランダムに選ばれてトランザクションを検証する。
- PoP(Proof of Place)の検証: 選ばれた代表者がトランザクションのPoP証明を検証する。これにより、送信者が指定された場所にいることが確認される。
- トランザクションの承認: トランザクションの内容とPoP証明が正しいと確認された場合、代表者がトランザクションを承認する。
1.3 トランザクション承認フェーズ
誰が: Municipal_Chainの代表者
何を: トランザクションを承認し、Continental_Main_Chainに送信
いつ: 検証フェーズが完了した後
どのように:
- トランザクションのContinental_Main_Chainへの送信: Municipal_Chainで代表者がトランザクションを承認すると、そのトランザクションはContinental_Main_Chainに送信される。
- PoH(Proof of History)の生成: 承認されたトランザクションは、PoHによってタイムスタンプが記録され、履歴が保証される。
2. Continental Main Chainの設計
Continental_Main_Chainは、大陸ごとに存在し、Municipal_Chainから送信されたトランザクションを一時的に保留し、受信者がそのトランザクションを受信する際に処理を完了する。
2.1 トランザクション保留フェーズ
誰が: Continental_Main_Chain
何を: Municipal_Chainから送信されたトランザクションを一時的に保留
どのように:
- トランザクションの受信: Continental_Main_Chainは、Municipal_Chainから送信されたトランザクションを受信し、それを保留リストに追加する。
- MongoDBへの保存: 保留されたトランザクションは、MongoDBに保存される。これにより、受信者がトランザクションを受信するまでデータが保護される。
2.2 トランザクション受信フェーズ
誰が: トランザクションの受信者
何を: トランザクションの受信を確認し、Continental Main Chainに通知
どのように:
- 受信信号の送信: 受信者がトランザクションを受け取りたい場合、DAppsを介して受信信号を送信する。この信号がContinental_Main_Chainに届くと、該当するトランザクションがMunicipal_Chainに返される。
- Municipal_Chainへの送信: Continental_Main_Chainは、該当するMunicipal_Chainにトランザクションデータを送信する。
2.3 トランザクション完了フェーズ
誰が: Municipal Chainの代表者とContinental Main Chain
何を: トランザクションの完了を確定し、愛貨を交換
どのように:
- Municipal Chainでの承認: 受信者のMunicipal Chainで、再度代表者が選出され、トランザクションが承認される。
- 愛貨の交換: トランザクションが承認されると、愛貨が送信者から受信者に移動する。これでトランザクションは完了し、データがMongoDBから削除される。
3. Rustコード設計
3.1 Municipal Chainの実装
Municipal Chainは、トランザクションの提案、検証、承認を行う。
use std::collections::HashMap;
use rand::seq::SliceRandom;
use tokio::sync::Mutex;
use rocket::State;
use rocket::serde::json::Json;
use rocket::http::Status;
use std::sync::Arc;
#[derive(Clone, Debug)]
struct Transaction {
transaction_id: String,
sender: String,
receiver: String,
amount: f64,
pop_proof: String,
timestamp: String,
municipality: String,
// その他のフィールド...
}
struct Representative {
id: u32,
name: String,
verified: bool,
}
struct MunicipalChain {
representatives: Vec<Representative>,
transactions: HashMap<String, Transaction>,
approvals: HashMap<String, u32>,
}
impl MunicipalChain {
fn new(representatives: Vec<Representative>) -> Self {
Self {
representatives,
transactions: HashMap::new(),
approvals: HashMap::new(),
}
}
fn propose_transaction(&mut self, transaction: Transaction) {
self.transactions.insert(transaction.transaction_id.clone(), transaction.clone());
self.approvals.insert(transaction.transaction_id.clone(), 0);
self.verify_transaction(transaction.transaction_id.clone());
}
fn verify_transaction(&mut self, transaction_id: String) {
if let Some(transaction) = self.transactions.get(&transaction_id) {
let mut rng = rand::thread_rng();
let selected_representative = self.representatives.choose_mut(&mut rng).unwrap();
println!("Representative {} selected for verification", selected_representative.name);
if self.validate_pop(transaction) {
selected_representative.verified = true;
*self.approvals.get_mut(&transaction_id).unwrap() += 1;
} else {
println!("Transaction {} verification failed", transaction_id);
}
self.check_approval_status(transaction_id);
}
}
fn validate_pop(&self, transaction: &Transaction) -> bool {
!transaction.pop_proof.is_empty()
}
fn check_approval_status(&self, transaction_id: String) {
let required_approvals = self.representatives.len() / 2 + 1;
if let Some(&approval_count) = self.approvals.get(&transaction_id) {
if approval_count >= required_approvals as u32 {
println!("Transaction {} is fully approved", transaction_id);
// Continental Main Chainに送信
} else {
println!("Transaction {} requires more approvals", transaction_id);
}
}
}
}
3.2 Continental_Main_Chainの実装
Continental_Main_Chainは、Municipal_Chainから送信されたトランザクションを受信し、受信者からの信号を待つ。
use rocket::serde::json::Json;
use rocket::State;
use rocket::http::Status;
use tokio::sync::Mutex;
use std::sync::Arc;
use mongodb::{bson::doc, Client as MongoClient, Collection};
use mongodb::bson::Document;
use std::collections::HashMap;
#[derive(Clone, Debug)]
struct Transaction {
transaction_id: String,
sender: String,
receiver: String,
amount: f64,
municipality: String,
// その他のフィールド...
}
#[derive(Clone)]
struct AppState {
pending_transactions: Arc<Mutex<HashMap<String, Transaction>>>,
mongo_collection: Collection<Document>,
}
async fn save_transaction_to_mongo(transaction: &Transaction, collection: &Collection<Document>) -> Result<(), mongodb::error::Error> {
let doc = doc! {
"transaction_id": &transaction.transaction_id,
"sender": &transaction.sender,
"receiver": &transaction.receiver,
"amount": &transaction.amount,
"municipality": &transaction.municipality,
// その他のフィールド...
};
collection.insert_one(doc, None).await?;
Ok(())
}
#[post("/receive_transaction", format = "json", data = "<transaction>")]
async fn receive_transaction(
transaction: Json<Transaction>,
state: &State<Arc<Mutex<AppState>>>
) -> Status {
let transaction = transaction.into_inner();
let mut state = state.lock().await;
if let Err(e) = save_transaction_to_mongo(&transaction, &state.mongo_collection).await {
println!("Failed to save transaction: {:?}", e);
return Status::InternalServerError;
}
state.pending_transactions.insert(transaction.transaction_id.clone(), transaction.clone());
Status::Accepted
}
#[post("/query_transaction", format = "json", data = "<query>")]
async fn query_transaction(
query: Json<Transaction>,
state: &State<Arc<Mutex<AppState>>>
) -> Status {
let mut state = state.lock().await;
if let Some(transaction) = state.pending_transactions.remove(&query.transaction_id) {
let municipal_chain_url = format!("http://{}/receive_transaction", transaction.receiver);
let client = Client::new();
let res = client.post(&municipal_chain_url).json(&transaction).send().await;
if res.is_ok() {
Status::Accepted
} else {
Status::InternalServerError
}
} else {
Status::NotFound
}
}
4. まとめ
この設計では、Municipal_ChainとContinental_Main_Chainが連携して、トランザクションが安全かつ効率的に処理されることを目指す。Municipal_Chainはトランザクションの提案から承認までを行い、Continental_Main_Chainはトランザクションを一時的に保留し、受信者がそのトランザクションを受け取るときに処理を完了する。
いかがであろうか、合意形成フローはシンプルだが、ここにセキュリティやら署名やらDBの認証やら、いろんなものが入ってくる。まずは、このシンプルな合意形成フローが基本設計となる。