はじめに
Rustが10周年を迎えました。
え?それは2025年のことだって?
「Rust 1.0」が米国時間2015年5月15日ので、Rust10周年は2025年5月15日~2026年5月16日までとなります。
ギリギリまだ10周年です。
で、ここからがこの記事の本題になりますが、マイニングの箇所をRustで書いてみるというのが、この記事で書くことです。
そもそもRustというプログラミング言語は速くて、安全性のあるプログラミング言語です。
前回、pythonのみでビットコインのマイニングまでを検証してみました。
試してみると、difficultyを7にすると、完了までに1562651.72 msかかります。
1562秒。
26分。
結構かかりました。
Rustのコード
では、早速、Rustのコードを書きます。
AIに手伝ってもらって以下のコードをpythonの元のコードに入れました。もともとマイニングをする箇所を差し替えています。(元のコードは以前の記事を参照してみてください)
def mine_block_with_rust(index: int, prev_hash: str, txs: List[Dict[str, Any]], difficulty: int) -> Block | None:
merkle_root = compute_merkle_root(txs)
payload = {
"index": index,
"prev_hash": prev_hash,
"difficulty": difficulty,
"merkle_root": merkle_root,
}
try:
proc = subprocess.run(
["rust_miner/target/release/rust_miner"],
input=json.dumps(payload).encode("utf-8"),
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
check=True,
)
except Exception as e:
log("miner", f"rust miner failed ({e}), falling back to Python miner")
return mine_block(index, prev_hash, txs, difficulty)
stdout = proc.stdout.decode("utf-8").strip()
if not stdout:
return None
try:
res = json.loads(stdout)
except json.JSONDecodeError as e:
log("miner", f"failed to decode rust miner output ({e}), falling back to Python miner")
return mine_block(index, prev_hash, txs, difficulty)
nonce = int(res["nonce"])
timestamp = float(res["timestamp"])
block_hash = str(res["hash"])
return Block(
index=index,
prev_hash=prev_hash,
timestamp=timestamp,
nonce=nonce,
difficulty=difficulty,
merkle_root=merkle_root,
txs=txs,
hash=block_hash,
)
subprocessで外部のrustを実行していて、その結果をstdout = proc.stdout.decode("utf-8").strip()として取得しています。
また、Rust側のプログラムは以下の様になっています。
use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
use std::error::Error;
use std::io::{self, Read};
use std::time::{SystemTime, UNIX_EPOCH};
#[derive(Deserialize)]
struct MineRequest {
index: u64,
prev_hash: String,
difficulty: u32,
merkle_root: String,
}
#[derive(Serialize)]
struct MineResponse {
nonce: u64,
timestamp: f64,
hash: String,
}
fn sha256d_hex(data: &[u8]) -> String {
let first = Sha256::digest(data);
let second = Sha256::digest(&first);
hex::encode(second)
}
fn build_header(req: &MineRequest, nonce: u64, timestamp: f64) -> Vec<u8> {
let s = format!(
"{}|{}|{}|{}|{}|{}",
req.index, req.prev_hash, timestamp, nonce, req.difficulty, req.merkle_root
);
s.into_bytes()
}
fn main() -> Result<(), Box<dyn Error>> {
let mut buf = String::new();
io::stdin().read_to_string(&mut buf)?;
if buf.trim().is_empty() {
return Ok(());
}
let req: MineRequest = serde_json::from_str(&buf)?;
let target_prefix = "0".repeat(req.difficulty as usize);
let mut nonce: u64 = 0;
loop {
let now = SystemTime::now().duration_since(UNIX_EPOCH)?;
let timestamp = now.as_secs_f64();
let header = build_header(&req, nonce, timestamp);
let hash_hex = sha256d_hex(&header);
if hash_hex.starts_with(&target_prefix) {
let resp = MineResponse {
nonce,
timestamp,
hash: hash_hex,
};
let out = serde_json::to_string(&resp)?;
println!("{}", out);
break;
}
nonce = nonce.wrapping_add(1);
}
Ok(())
}rust_minerフォルダに移動して、
cargo build --releaseを実行
その後、pythonで前回と同様にデモを実施しました。
結果なんですが、
355791.75 ms
で完了しました。
355秒。
6分ほどで完了ということで、pythonで実装したときの26分と比べて4分の1以上速くなったことを確認しました。
最後に
めっちゃ速くなりましたね!
Rust凄いっす!
