skka3134

skka3134

email
telegram

Rustでシンプルなブロックチェーンを開発する

ブロックチェーンのシンプルな構造は、無数のこのようなブロックが鎖のように繋がって構成されていると簡単に理解できます。
image

image
その中で緑の部分はブロックヘッダーと呼ばれ、(pre hash, tx hash, time)を含みます。
黒い部分と青い部分はブロックボディと呼ばれ、(hash, transaction)を含みます。

その中で pre hash は前のブロックの hash です。
time は取引時間、タイムスタンプを表します。
tx hash はデータが改ざんされないことを保証するために使用されます。理論的には各ブロックのデータは改ざん可能ですが、変更すると hash が一致しなくなります。
transaction は取引情報です。
最後は全体のブロックのハッシュ値で、この値は各ブロックの識別子に相当します。同じく、ブロック内のデータの 1 つでも変更すれば、ハッシュ値は変わります。

コードを書きましょう!!!

  1. まず、必要なパッケージを使用して、ターミナルを開きます。
cargo add serde 
cargo add bincode
cargo add rust-crypto
cargo add chrono
  1. パッケージ serde はシリアライズとデシリアライズに使用されます。シリアライズとデシリアライズは非常に一般的な機能で、ネットワーク伝送やデータストレージで非常に一般的です。シリアライズとデシリアライズの一般的な説明は次のとおりです:シリアライズ:オブジェクトを転送しやすい形式に変換します。一般的なシリアライズ形式には、バイナリ形式、バイト配列、json 文字列、xml 文字列があります。デシリアライズ:シリアライズされたデータをオブジェクトに戻すプロセスです。
    パッケージ bincode はバイナリのエンコーディング形式です。
    パッケージ crypto はハッシュを求めるためのものです。
    パッケージ chrono はタイムスタンプを求めるためのものです。

  2. 頂部に以下のコードを追加します。

use bincode;
use serde::{Deserialize, Serialize};
use crypto::digest::Digest;
use crypto::sha3::Sha3;
use chrono::prelude::*;
  1. ブロックヘッダーを定義します。
 struct BlockHeader {
     time: i64,
     tx_hash: String,
     pre_hash: String,
}
  1. ブロックを定義します。
 struct Block {
     header: BlockHeader,
     hash: String,
     data: String, //transactions data
}
  1. 先ほど追加したパッケージを使用して、1 つのシリアライズと 1 つのデシリアライズのメソッドを作成します。
//シリアライズ
fn my_serialize<T: ?Sized>(value: &T) -> Vec<u8> 
    where T: Serialize,
{
    let seialized = bincode::serialize(value).unwrap();
    seialized
}
//デシリアライズ
fn my_deserialize<'a, T>(bytes: &'a[u8]) -> T 
    where T: Deserialize<'a>,
{
    let deserialized = bincode::deserialize(bytes).unwrap();
    deserialized
}
  1. パッケージ rust-crypto を使用してハッシュを求めます。
fn get_hash(value: &[u8]) -> String {
    let mut hasher = Sha3::sha3_256();
    hasher.input(value);
    hasher.result_str()
}
  1. 以前に定義した Block にこれらのメソッドを実装します。
impl Block {
    fn set_hash(&mut self) {
        let header = coder::my_serialize(&(self.header));
        self.hash = coder::get_hash(&header[..]);
    }

     fn new_block(data: String, pre_hash: String) -> Block {
        let transactions = coder::my_serialize(&data);
        let tx_hash = coder::get_hash(&transactions[..]);

        let time = Utc::now().timestamp();

        let mut block = Block {
            header: BlockHeader {
                time: time,
                tx_hash: tx_hash,  //transactions data merkle root hash
                pre_hash: pre_hash,
            },
            hash: "".to_string(),
            data: data,
        };

        block.set_hash();
        block
    }
}
  1. ブロックチェーンを定義します。
struct BlockChain {
    blocks: Vec<block::Block>,
}
impl BlockChain {
   fn add_block(&mut self, data: String) {
        let pre_block = &self.blocks[self.blocks.len() - 1];
        let new_block = block::Block::new_block(data, pre_block.hash.clone());
        self.blocks.push(new_block);
    }

    fn new_genesis_block() -> block::Block {
        block::Block::new_block("これは創世ブロックです".to_string(), String::from(""))
    }

     fn new_blockchain() -> BlockChain {
        BlockChain {
            blocks: vec![BlockChain::new_genesis_block()],
        }
    }
}
  1. メインメソッドを定義します。
fn main() {
    let mut bc = blockchain::BlockChain::new_blockchain();
    bc.add_block(String::from("a -> b: 5 btc"));
    bc.add_block("c -> d: 1 btc".to_string());
    for b in bc.blocks {
        println!("++++++++++++++++++++++++++++++++++++++++++++");
        println!("{:#?}", b);
        println!("");
    }
}

最後のコードは次のようになります。

use bincode;
use serde::{Deserialize, Serialize};
use crypto::digest::Digest;
use crypto::sha3::Sha3;
use chrono::prelude::*;

 struct BlockHeader {
     time: i64,
     tx_hash: String,
     pre_hash: String,
}

 struct Block {
     header: BlockHeader,
     hash: String,
     data: String, //transactions data
}
impl Block {
    fn set_hash(&mut self) {
        let header = coder::my_serialize(&(self.header));
        self.hash = coder::get_hash(&header[..]);
    }

     fn new_block(data: String, pre_hash: String) -> Block {
        let transactions = coder::my_serialize(&data);
        let tx_hash = coder::get_hash(&transactions[..]);

        let time = Utc::now().timestamp();

        let mut block = Block {
            header: BlockHeader {
                time: time,
                tx_hash: tx_hash,  //transactions data merkle root hash
                pre_hash: pre_hash,
            },
            hash: "".to_string(),
            data: data,
        };

        block.set_hash();
        block
    }
}

//シリアライズ
fn my_serialize<T: ?Sized>(value: &T) -> Vec<u8> 
    where T: Serialize,
{
    let seialized = bincode::serialize(value).unwrap();
    seialized
}
//デシリアライズ
fn my_deserialize<'a, T>(bytes: &'a[u8]) -> T 
    where T: Deserialize<'a>,
{
    let deserialized = bincode::deserialize(bytes).unwrap();
    deserialized
}

fn get_hash(value: &[u8]) -> String {
    let mut hasher = Sha3::sha3_256();
    hasher.input(value);
    hasher.result_str()
}

struct BlockChain {
    blocks: Vec<block::Block>,
}

impl BlockChain {
    fn add_block(&mut self, data: String) {
        let pre_block = &self.blocks[self.blocks.len() - 1];
        let new_block = block::Block::new_block(data, pre_block.hash.clone());
        self.blocks.push(new_block);
    }

    fn new_genesis_block() -> block::Block {
        block::Block::new_block("これは創世ブロックです".to_string(), String::from(""))
    }

     fn new_blockchain() -> BlockChain {
        BlockChain {
            blocks: vec![BlockChain::new_genesis_block()],
        }
    }
}

cargo run すると、結果は次のようになります。
image
もしマイニングをシミュレートしたい場合は、sleep で約 10 秒間休止してください。

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。