先までは、"愛記"についての記載で、どのようにブロックチェーンSNSに組み込んで実装していけばよいのか、概念的なところからアプローチ方法を記載していった。大まかな概念としてはひとまず終えた。次は、ブロックチェーンの概念設計といえるところまで、基本設計書に着手できるようなところまで、概念を具体化していきたい。
愛記システムのシステム評価について
システム評価とは、つまりは、このシステムを導入して成功だったか失敗だったかという効果検証という意味だ。概念設計をする上で必ず抑えておくべきポイントということだ。それには各項目があり、それぞれの項目を見ていくことで、その結果が得られる。そのシステム評価項目を1つずつ見ていきたい。
システム構築の品質評価のポイント1:理解可能性(Understandability)
システム構築の品質評価のポイント2:完全性(Completeness)
システム構築の品質評価のポイント3:簡潔性(Conciseness)
システム構築の品質評価のポイント4:移植性(Portability)
システム構築の品質評価のポイント5:一貫性(Consistency)と構造化の度合い
システム構築の品質評価のポイント6:保守性(Maintainability)
システム構築の品質評価のポイント7:試験性(Testability)
システム構築の品質評価のポイント8:ユーザビリティ(Usability)
システム構築の品質評価のポイント9:効率性(Efficiency)
システム構築の品質評価のポイント10:セキュリティ(Security)
システム構築の品質評価のポイント7:試験性④(Testability)
システム構築の品質評価ポイントとなっている試験性とは、不具合があるかどうかを確認するための各種テスト項目が簡単に実施できるかどうかである。不具合があった際にその不具合が階層まで調査する必要があり、見つけるまで非常に時間がかかるのは問題である。この試験性は先ほど記載した保守性と非常に関連性があり、試験性の高さは保守性の高さに繋がる。逆に低いと保守性の品質評価も下がる。
さて、試験性の定義として、7つの特性があるのでそれぞれについて見ていこう。
- 実行円滑性(Operability)
- 観測容易性(Observability)
- 制御容易性(Controllability)
- 分解容易性(Decomposability)
- 単純性(Simplicity)
- 安定性(Stability)
- 理解容易性(Understandability)
これらの特性はJames Bach著『ソフトウェアテスト293の法則』やRoger S. Pressman著『実践ソフトウェアエンジニアリング』 で挙げられている。
6. 安定性(Stability)
同じ条件や環境で何度テストしても、一貫した振る舞いができるかという特性である。なお、コンポーネントの安定度についても、実行結果が不安定ではないことを含む。例えば次のような状況は、安定性が低い。
・変更が頻繁で、テストへの影響が大きい
・外部環境へアクセスしたり、乱数や時刻を使用したりして、同じ条件下でも結果が安定しない
ここもまさにであり、安定性が低いと言える。バリデーター問題など、常に不安定な中で如何に安定させるかということが課題となる。
具体的には、各バリデーターがトランザクションを検証し、安定性を判断している。ブロックチェーンにおいては、トランザクションの検証やブロックの生成などが重要な機能である。安定性を確保するために、バリデーターのコンポーネントが変更に頻繁に対応することなく、テストの影響を最小限に抑えつつ、外部環境の不確実性に対処する方法を検討する。以下は、この課題に対処するためのアプローチの例である。
-
変更の最小化: バリデーターのコンポーネントが変更に強くなるように、コードのモジュラリティを高め、機能を適切な粒度に分割する。これにより、変更が頻繁に発生しても、影響範囲を限定できる。
-
テストの自動化: バリデーターのコンポーネントに対して十分なテストカバレッジを確保し、変更が行われた際に影響を検知できるようにする。これにより、変更があってもテストが早期にフィードバックを提供し、不安定性を減少させる。
-
外部環境の制御: 外部環境へのアクセスや乱数、時刻の使用に関しては、これらを制御可能な形に変更する。外部依存を最小限にし、制御できるパラメータや設定を導入することで、同じ条件下での結果の安定性を向上させる。
以下は、この例では、perform_validationメソッド内で外部環境に依存せず、内部で乱数を生成している。これにより、外部環境の変動に対してコンポーネントが安定した振る舞いを示すことが期待される。
# フェデレーションモデルにおける安定性向上のプログラミング例
import random
class Validator:
def __init__(self, validator_id):
self.validator_id = validator_id
self.stability_threshold = 0.95 # 安定性のしきい値
def validate_transaction(self, transaction):
# トランザクションの検証ロジック
validation_result = self.perform_validation(transaction)
# 安定性の計算と判断
stability = self.calculate_stability(validation_result)
if stability >= self.stability_threshold:
return True # トランザクションが安定している場合は承認
else:
return False # トランザクションが不安定な場合は非承認
def perform_validation(self, transaction):
# 実際のトランザクション検証ロジック
# 例えば、外部環境に依存せず、内部で乱数を生成するなど
random_value = self.generate_random_value()
if random_value > 0.5:
return True
else:
return False
def calculate_stability(self, validation_result):
# 安定性の計算ロジック
# 例えば、過去の検証結果を利用して安定性を算出するなど
pass
def generate_random_value(self):
# 外部環境に依存しない乱数生成
return random.uniform(0, 1)
# 利用例
# バリデーターのインスタンス化
validator_A = Validator("Validator A")
# 安定性が高い場合のトランザクション
stable_transaction = {...} # トランザクションデータの例
result_stable = validator_A.validate_transaction(stable_transaction)
print("安定性が高いトランザクション:", result_stable)
# 安定性が低い場合のトランザクション
unstable_transaction = {...} # トランザクションデータの例
result_unstable = validator_A.validate_transaction(unstable_transaction)
print("安定性が低いトランザクション:", result_unstable)
7. 理解容易性(Understandability)
ソフトウェアの構造と動作をどれだけ容易に理解できるかという特性である。例えば次のような状況は、安定性が低い。
・適切ではない命名
・過剰な複雑性
・ドキュメントやコメントの不足
理解することすら難しいPoHやPoSというアルゴリズムだけでなく、ネットワークも複雑に絡んでいくため、容易に理解できない。極めて難しいシステムと言える。理解可能性の向上のために、以下のアプローチが取られることがある。これをフェデレーションモデルに適用すると、コンポーネントやアルゴリズムの理解を助ける手段となる。
-
適切な命名規則の採用: 適切な変数や関数の命名規則を採用し、コード内の各要素が意味を持つようにする。例えば、PoH(Proof of History)やPoS(Proof of Stake)に関連するコンポーネントには、その機能や役割に応じた具体的な名前を与える。
-
過剰な複雑性の排除: コードやアルゴリズムが過剰に複雑であれば、それをシンプルな構造に再設計する。特に、関数やモジュールの分割、コードのリファクタリング、不要な機能の削除などが有効である。
-
ドキュメントとコメントの追加: コードには十分なコメントとドキュメンテーションを追加する。アルゴリズムやコンポーネントの動作、特にPoHやPoSなどの複雑なアルゴリズムに関する詳細な説明を提供する。これにより、他の開発者やメンテナンス担当者が理解しやすくなる。
-
教育とトレーニング: チームメンバーに対して、新しい概念やアルゴリズムについての教育とトレーニングを提供する。特に、新しい技術やアルゴリズムを導入する際には、関連するトレーニングプログラムを利用することが役立つ。
以下の例では、まずは定期的にDPoSで承認者である市町村の代表者を選出する。たとえば、3か月ごととか。選ばれた代表はフェデレーションモデルでメインブロックチェーンにあがってくる各市町村からのブロックを承認する。その承認プロセスは、各市町村は独立したブロックチェーンであり、Proof of Placeで行為者の場所を特定しつつトランザクションが形成され、そのトランザクションにPoHにてタイムスタンプが組み合わされてトランザクションが次に送られる。 -
Proof of Place (PoP):
- ユーザーがトランザクションを送信するときに、位置情報を収集し、それをPoPによってブロックチェーンに登録します。これにより、トランザクションが特定の場所で実行されたことが証明される。この位置情報を加えることで、ハッキングするにも特定の位置に居なければならないため、遠隔操作でのハッキングは極めて難しくなり、セキュリティが向上する。なお、以下に、提供されたトランザクションデータの構造について説明しよう。
-
トランザクションID(Transaction ID):
- 機能: トランザクションを一意に識別するためのユニークなID。
- データ型: 文字列(String)
-
ユーザーアカウント(User Account):
- 機能: トランザクションを送信したユーザーのアカウント情報。
- データ型: アカウント情報(例: ユーザー名、アカウント番号など)
-
署名(Signature):
- 機能: トランザクションが有効であることを確認するためのデジタル署名。
- データ型: デジタル署名データ(例: RSA、ECDSAなど)
-
トランザクションの前提条件(Preconditions):
- 機能: トランザクションが実行される前に満たされている必要がある条件。
- データ型: 条件に関する情報
-
位置(GIS):
- 機能: トランザクションが作成されたときの位置情報。
- データ型: 地理情報システム(GIS)データ(例: 緯度経度、住所など)
-
愛の行動レベル(Love Action Level):
- 機能: トランザクションの愛に関する行動のレベルを示す数値と科目。
- データ型: 数値やカテゴリ情報
-
次元(Dimension):
- 機能: 生命体の次元を表す識別子やカテゴリ。
- データ型: 識別子やカテゴリ情報(例: 次元ID)
-
愛貨額(Amount):
- 機能: 提案されたトランザクションの愛貨額。
- データ型: 数値(例: 愛貨額)
-
行動内容(Action Content):
- 機能: 実際の行動や提案された行動の詳細な説明。
- データ型: 文字列やテキスト
-
承認相手(Approval Target):
- 機能: 行動の承認を得る対象のアドレスやID。
- データ型: アカウント情報
-
ゆらぎ(Fluctuation):
- 機能: 新たな生命体の発起活動。
- データ型: 活動や変化に関する情報
-
各要素はトランザクションの特定の側面を表しており、これらのデータを組み合わせてトランザクション全体を形成する。この構造は、特定のシステムやプロトコルに応じて変更される可能性がある。
-
Proof of History (PoH):
- 続いて、トランザクションのタイムスタンプ情報を利用して、PoHを生成する。これにより、トランザクションが時間の流れに沿って順序付けられ、過去のトランザクションの履歴がブロックチェーンに確実に反映される。
-
Delegated Proof of Stake (DPoS):
- ネットワークのブロック生成者や承認者を選出するためにDPoSを導入する。DPoSでは、ネットワークの一部のノードがブロック生成の権限を持ち、これらのノードが投票によって選出される。これにより、ブロック生成者が分散されつつも、一定の効率とスケーラビリティを確保できる。
-
メインチェインでの承認:
- DPoSによって選ばれた代表者がトランザクションをブロックにまとめ、メインチェインに提出する。メインチェイン上でトランザクションが承認され、ブロックが追加される。このようなアルゴリズムを組み合わせることで、位置情報、時間の経過、代表者の選出によりトランザクションの信頼性を高めつつ、分散型で効率的なブロックチェーンネットワークを構築できる。ただし、これらの要素を組み合わせる際には、セキュリティやパフォーマンスに関する検討が重要である。
use chrono::{DateTime, Utc};
use sha2::{Digest, Sha256};
use std::collections::{HashMap, HashSet};
use std::time::Duration;
// トランザクション結果
#[derive(Debug)]
enum TransactionResult {
Success,
Failure,
}
// Verifiable Credentialの構造体
#[derive(Debug, Clone)]
struct VerifiableCredential {
user_id: String,
claim_data: HashMap<String, String>,
timestamp: DateTime<Utc>,
}
// Blockchainトレイト
trait Blockchain {
fn store_credential(&self, credential: &VerifiableCredential) -> Option<TransactionResult>;
fn update_shared_credential(&self, recipient_id: &str, credential: &VerifiableCredential) -> Option<TransactionResult>;
fn select_block_producers(&self) -> Vec<String>;
}
// Blockchainのダミー実装
struct DummyBlockchain;
impl Blockchain for DummyBlockchain {
fn store_credential(&self, _credential: &VerifiableCredential) -> Option<TransactionResult> {
Some(TransactionResult::Success)
}
fn update_shared_credential(&self, _recipient_id: &str, _credential: &VerifiableCredential) -> Option<TransactionResult> {
Some(TransactionResult::Success)
}
}
// VerifiableCredentialManagerクラス
struct VerifiableCredentialManager<T: Blockchain> {
blockchain: T,
}
impl<T: Blockchain> VerifiableCredentialManager<T> {
fn new(blockchain: T) -> Self {
VerifiableCredentialManager {
blockchain,
credentials: HashMap::new(),
}
}
fn create_verifiable_credential(&mut self, user_id: String, claim_data: HashMap<String, String>) {
let credential = VerifiableCredential {
user_id: user_id.clone(),
claim_data: claim_data.clone(),
timestamp: Utc::now(),
};
if let Some(transaction_result) = self.blockchain.store_credential(&credential) {
self.credentials.insert(user_id, credential.clone());
println!("Verifiable Credential created and stored for user {}.", user_id);
} else {
println!("Failed to store Verifiable Credential.");
}
}
fn share_verifiable_credential(&mut self, user_id: &str, recipient_id: &str) {
if let Some(credential_to_share) = self.credentials.get(user_id) {
if let Some(update_result) = self.blockchain.update_shared_credential(recipient_id, credential_to_share) {
println!("Verifiable Credential shared with user {}.", recipient_id);
} else {
println!("Failed to share Verifiable Credential.");
}
} else {
println!("No Verifiable Credential found for user {}.", user_id);
}
}
}
// APIの実装
struct LoveCurrencyApi;
blockchain_client: YourBlockchainClient, // ブロックチェーンと通信するクライアント
}
impl LoveCurrencyApi {
// メインチェーンから自治体のブロックチェーンにデータを送信するメソッド
fn send_data_to_municipality_chain(transaction: &Transaction, municipality: &str) {
if transaction.verify_signature() {
println!("Sending data to municipality chain: {:?}", transaction);
// メインチェーンから自治体のブロックチェーンにデータを送信する処理を実装する
// ここで自治体のブロックチェーンにデータを送信する処理を実装する
match self.blockchain_client.send_transaction_to_municipality_chain(transaction, municipality) {
Ok(_) => println!("Data sent successfully."),
Err(err) => println!("Failed to send data: {:?}", err),
}
} 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
}
// 新しいエンドポイントを追加して、リクエストを受け取ってからapprove_requestメソッドを呼び出す
fn approve_request_from_municipality(data: &Transaction) {
if data.verify_signature() {
println!("Received approval request from municipality: {:?}", data);
let mut dummy_blockchain = DummyBlockchain;
dummy_blockchain.store_credential(&VerifiableCredential {
user_id: "UserA".to_string(),
claim_data: HashMap::new(),
timestamp: Utc::now(),
});
// 実際には、リクエストを処理するロジックを実装する
} else {
println!("Failed to approve request: Invalid signature");
}
}
}
// トランザクションの構造体
#[derive(Debug)]
struct Transaction {
transaction_id: String,
municipality: String,
timestamp: DateTime<Utc>,
location: (f64, f64), // 緯度と経度を表すタプル
love_action_level: u32,
amount: f64,
action_content: String,
is_local: bool,
close_flag: bool,
approval_target: Option<String>,
sender_public_key: String, // 送信者の公開鍵
receiver_public_key: String, // 受信者の公開鍵
signature: String, // 署名
location_hash: Vec<u8>,
received_timestamp: Option<DateTime<Utc>>,
recipient_location: Option<(f64, f64)>, // 受信時の位置情報を保持するフィールドを追加
fee: f64, // 手数料を追加
}
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 calculate_fee(&self) -> f64 {
self.amount * 0.01 // 例として手数料を1%に設定
}
// トランザクション手数料を表示するメソッド
fn display_fee(&self) {
let fee = self.calculate_fee();
println!("Transaction fee: {} 愛貨", fee);
}
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.sender_public_key, // 送信者の公開鍵を追加
self.receiver_public_key, // 受信者の公開鍵を追加
self.approval_target.as_deref().unwrap_or(""), self.signature,
);
self.signature = 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);
// 愛貨トークンを受け取る処理を実装する
decreased_amount
}
fn verify_signature(&self) -> bool {
// 署名を検証する処理を実装する
true
}// 位置情報が境界内かどうかを判定
fn is_within_boundary(&self, boundary: &((f64, f64), (f64, f64))) -> bool {
// 境界の座標を定義
let boundary = ((35.6, 139.6), (35.7, 139.7));
let ((min_lat, min_lon), (max_lat, max_lon)) = boundary;
location.0 >= min_lat && location.0 <= max_lat && location.1 >= min_lon && location.1 <= max_lon
}
// 受信時の位置情報をセットするメソッドfn set_recipient_location(&mut self, location: (f64, f64)) {
self.recipient_location = Some(location);
}
}
fn main() {
// MainChainを直接初期化
let main_chain = MainChain::new(Duration::from_secs(10)); // 例としてブロック生成間隔を10秒に設定
let mut transaction = Transaction {
// ...既存フィールドの初期化...
fee: 0.0, // 初期値として0.0を設定
};
transaction.calculate_location_hash();
transaction.generate_signature();
transaction.fee = transaction.calculate_fee(); // 手数料を計算
}
// メインチェーンの構造体
struct MainChain {
federated_blockchains: HashMap<String, Federation>,
pending_transactions: HashMap<String, Transaction>,
received_transactions: HashSet<String>,
delegates: Vec<String>, // デリゲート(ブロック生成者)のリスト
active_delegates: Vec<String>, // 現在のアクティブなデリゲートのリスト
voters: HashMap<String, Vec<String>>, // 各デリゲートに対する投票者のリスト
block_time: Duration, // ブロックの生成間隔
}
impl MainChain {
fn new(block_time: Duration) -> Self {
MainChain {
federated_blockchains: HashMap::new(),
pending_transactions: HashMap::new(),
received_transactions: HashSet::new(),
delegates: Vec::new(),
active_delegates: Vec::new(),
voters: HashMap::new(),
block_time,
}
}
// 新しいブロックを生成するメソッド
fn create_block(&mut self, delegate: &str) {
if self.active_delegates.contains(&delegate.to_string()) {
// 新しいブロックを生成する処理を実装する
println!("New block created by delegate {}.", delegate);
} else {
println!("Delegate {} is not active.", delegate);
}
}
// メインチェーンから自治体のブロックチェーンにデータを送信
struct LoveCurrencyApi {
blockchain_client: YourBlockchainClient, // ブロックチェーンと通信するクライアント
federated_blockchains: HashMap<String, Federation>, // フェデレーションのリスト
}
impl LoveCurrencyApi {
// メインチェーンから自治体のブロックチェーンにデータを送信するメソッド
fn send_data_to_municipality_chain(&self, transaction: &Transaction, municipality: &str) {
if transaction.verify_signature() {
println!("Sending data to municipality chain: {:?}", transaction);
// ブロックチェーンクライアントを使ってデータを送信する処理を実装する
match self.blockchain_client.send_transaction_to_municipality_chain(transaction, municipality) {
Ok(_) => println!("Data sent successfully."),
Err(err) => println!("Failed to send data: {:?}", err),
}
} else {
println!("Failed to send data: Invalid signature");
}
}
// メインチェーンが自治体から承認シグナルを受信
fn receive_approval_signal(&mut self, transaction_id: &str, recipient_location: &(f64, f64)) {
if let Some(federation) = self.federated_blockchains.get_mut("municipality_chain") {
if let Some((transaction, sender_location)) = federation.pending_transactions.get(transaction_id) {
// 境界内かどうかを判定
if federation.is_within_boundary(&transaction.location) && federation.is_within_boundary(recipient_location) {
println!("Transaction {} approved by federation.", transaction_id);
// 承認処理を実装する
fn approve_transaction(&mut self, transaction_id: &str) -> Option<TransactionResult> {
if let Some(transaction) = self.pending_transactions.get(transaction_id) {
// トランザクション手数料を表示
transaction.display_fee();
// 送信者から手数料を差し引く(仮実装)
println!("Deducting fee of {} 愛貨 from sender {}", transaction.calculate_fee(), transaction.sender_public_key);
// トランザクションを承認
self.received_transactions.insert(transaction_id.to_string());
println!("Transaction {} approved.", transaction_id);
Some(TransactionResult::Success)
} else {
println!("Transaction {} not found.", transaction_id);
Some(TransactionResult::Failure)
}
}
// フェデレーションにトランザクションの承認シグナルを受信させる処理を実装する
} else {
println!("Transaction {} rejected by federation due to location validation failure.", transaction_id);
}
} else {
println!("Pending transaction not found with ID {}.", transaction_id);
}
} else {
println!("Federation not found for pending transaction with ID {}.", transaction_id);
}
}
}
// フェデレーションの構造体
struct Federation {
boundary: ((f64, f64), (f64, f64)),
pending_transactions: HashMap<String, (Transaction, (f64, f64))>,
}
impl Federation {
// 新規フェデレーションの作成
fn new(public_key: String, boundary: ((f64, f64), (f64, f64))) -> Self {
Federation {
public_key,
boundary,
pending_transactions: HashMap::new(),
}
}
// フェデレーションがペンディングトランザクションを処理
fn process_pending_transaction(&mut self, transaction_id: &str, recipient_location: &(f64, f64)) {
if let Some((transaction, sender_location)) = self.pending_transactions.remove(transaction_id) {
if self.is_within_boundary(recipient_location) && self.is_within_boundary(&sender_location) {
println!("Transaction {} approved by federation with public key {}.", transaction_id, self.public_key);
} else {
println!("Transaction {} rejected by federation with public key {} due to location validation failure.", transaction_id, self.public_key);
}
} else {
println!("Transaction {} not found in pending transactions.", transaction_id);
}
}
// フェデレーションがペンディングトランザクションの承認シグナルを受信
fn receive_approval_signal(&mut self, transaction_id: &str, recipient_location: &(f64, f64)) {
if let Some((transaction, sender_location)) = self.pending_transactions.get(transaction_id) {
if self.is_within_boundary(recipient_location) && self.is_within_boundary(&sender_location) {
println!("Received approval signal for transaction {} from federation with public key {}.", transaction_id, self.public_key);
} else {
println!("Received invalid approval signal for transaction {} from federation with public key {}.", transaction_id, self.public_key);
}
} else {
println!("Pending transaction not found with ID {} in federation with public key {}.", transaction_id, self.public_key);
}
}
// ペンディングトランザクションの存在確認
fn has_pending_transaction(&self, transaction_id: &str) -> bool {
self.pending_transactions.contains_key(transaction_id)
}
// 位置情報が境界内かどうかを判定
fn is_within_boundary(&self, location: &(f64, f64)) -> bool {
let ((min_lat, min_lon), (max_lat, max_lon)) = self.boundary;
location.0 >= min_lat && location.0 <= max_lat && location.1 >= min_lon && location.1 <= max_lon
}
}
- DPoSによって選ばれた代表者がトランザクションをブロックにまとめ、メインチェインに提出する。メインチェイン上でトランザクションが承認され、ブロックが追加される。このようなアルゴリズムを組み合わせることで、位置情報、時間の経過、代表者の選出によりトランザクションの信頼性を高めつつ、分散型で効率的なブロックチェーンネットワークを構築できる。ただし、これらの要素を組み合わせる際には、セキュリティやパフォーマンスに関する検討が重要である。
いかがであろうか、試験性が高い/低いとはどういう状態なのか?という点を整理してみたが、ブロックチェーンシステムの場合、試験性が極めて悪いと言える。ここがサーバーと大きな違いであろう。多くの人が介在して成り立つシステムであるがゆえ、実践環境でしか、本当のトラブルは発生しない。どんなに対処しても、人の悪行の問題も常につきまとう。こう考えると、やはり小規模から始めて徐々に規模を拡大していくしか、方法は無いようにも思える。