ブロックチェーンのシンプルな構造は、無数のブロックが鎖のように接続されてブロックチェーンを形成していると簡単に理解できます。
その中で、緑の部分はブロックヘッダーと呼ばれ、(pre hash, tx hash, time)を含みます。
黒い部分と青い部分はブロックボディと呼ばれ、(hash, transaction)を含みます。
その中で pre hash は前のブロックの hash です。
time は取引時間、タイムスタンプを表します。
tx hash はデータが改ざんされないようにするために使用されます。理論的には、各ブロックのデータは改ざん可能ですが、変更すると hash が一致しなくなります。
transaction は取引情報です。
最後は全体のブロックのハッシュ値で、この値は各ブロックの識別子に相当します。同じく、ブロック内のデータの 1 つでも変更すれば、ハッシュ値は変わります。
コードを書きましょう!!!
- まず、必要なパッケージを使用して、ターミナルを開きます。
cargo add serde
cargo add bincode
cargo add rust-crypto
cargo add chrono
-
パッケージ serde はシリアル化とデシリアル化に使用されます。シリアル化とデシリアル化は非常に一般的な機能で、ネットワーク伝送やデータストレージで極めて一般的です。シリアル化とデシリアル化の一般的な説明は次のとおりです:シリアル化:オブジェクトを転送しやすい形式に変換します。一般的なシリアル化形式:バイナリ形式、バイト配列、json 文字列、xml 文字列。デシリアル化:シリアル化されたデータをオブジェクトに戻すプロセスです。
パッケージ bincode はバイナリのエンコーディング形式です。
パッケージ crypto は hash を求めるためのものです。
パッケージ chrono はタイムスタンプを求めるためのものです。 -
上部に次のコードを追加します。
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
}
- 先ほど追加したパッケージを使用して、シリアル化とデシリアル化の 2 つのメソッドを作成します。
//シリアル化
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
}
- パッケージ rust-crypto を使用して hash を求めます。
fn get_hash(value: &[u8]) -> String {
let mut hasher = Sha3::sha3_256();
hasher.input(value);
hasher.result_str()
}
- 以前に定義した 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
}
}
- ブロックチェーンを定義します。
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()],
}
}
}
- メインメソッドを定義します。
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 すると、結果は次のようになります。
もしマイニングをシミュレートしたい場合は、sleep で約 10 秒間休止します。