# اول از همه؛ بیتکوین دقیقاً چه مشکلی را حل میکند؟
ده بار کپی کنید — کاملاً مشکلی ندارد
ده بار کپی کنید — دیگر پول نیست
# بلاکچین در سادهترین شکل چیست؟
# Hash چیست و چرا اینقدر مهم است؟
185f8db32271fe25f5...
2cf24dba5fb0a30e26e...
import hashlib
text = "Hello"
hash_value = hashlib.sha256(
text.encode()
).hexdigest()
print(hash_value)
# 185f8db32271fe25f5... (طول ثابت، ظاهراً تصادفی)
# اما فقط Hash کافی نیست؛ ورود Proof of Work
# Transaction چیست؟ آشنایی با مدل UTXO
Alice = 100 و از یک موجودی کم میکرد. اما بیتکوین واقعی از مدل ساده «موجودی حساب» استفاده نمیکند. مدل اصلی آن UTXO — Unspent Transaction Output است: خروجی یک تراکنش که هنوز خرج نشده است.
Alice = 100 BTC، تصور کنید Alice چند خروجی خرجنشده دارد:
# تراکنشها داخل بلاک کجا میروند؟ Merkle Tree
# حالا بیایید خودمان یک بیتکوین کوچک بسازیم
address رشتهای است. این برنامه برای یادگیری است، نه برای ساخت پول واقعی.
مرحله اول — توابع کمکی Hash
import hashlib
import json
import time
def sha256_hex(data: str) -> str:
return hashlib.sha256(data.encode()).hexdigest()
def canonical(obj) -> str:
return json.dumps(
obj,
sort_keys=True,
separators=(",", ":")
)
canonical مهم است: دادهای که Hash میشود باید همیشه با یک ترتیب ثابت Serialize شود تا همان داده، همیشه همان Hash را بدهد.
مرحله دوم — ساخت Transaction
from dataclasses import dataclass
@dataclass(frozen=True)
class TxInput:
txid: str
output_index: int
@dataclass(frozen=True)
class TxOutput:
address: str
amount: int
class Transaction:
def __init__(self, inputs, outputs):
self.inputs = inputs
self.outputs = outputs
def to_dict(self):
return {
"inputs": [
{"txid": i.txid,
"output_index": i.output_index}
for i in self.inputs
],
"outputs": [
{"address": o.address,
"amount": o.amount}
for o in self.outputs
]
}
@property
def txid(self) -> str:
return sha256_hex(
canonical(self.to_dict())
)
مرحله سوم — ساخت Merkle Root
class Block:
@staticmethod
def calculate_merkle_root_from_txids(txids):
if not txids:
return sha256_hex("")
level = txids[:]
while len(level) > 1:
if len(level) % 2 == 1:
level.append(level[-1]) # اگر فرد بود، آخری تکرار میشود
level = [
sha256_hex(
level[i] + level[i + 1]
)
for i in range(0, len(level), 2)
]
return level[0]
مرحله چهارم — ساخت Block و Header آن
class Block:
def __init__(self, index, transactions,
previous_hash, timestamp=None):
self.index = index
self.timestamp = (
time.time()
if timestamp is None
else timestamp
)
self.transactions = transactions
self.previous_hash = previous_hash
self.nonce = 0
self.merkle_root = (
self.calculate_merkle_root()
)
self.hash = ""
def header_dict(self):
return {
"index": self.index,
"timestamp": self.timestamp,
"merkle_root": self.merkle_root,
"previous_hash": self.previous_hash,
"nonce": self.nonce
}
def calculate_hash(self):
return sha256_hex(
canonical(self.header_dict())
)
مرحله پنجم — Mining
difficulty = 3، Hash باید با 000 شروع شود:
def mine(self, difficulty):
target = "0" * difficulty
while True:
self.hash = self.calculate_hash()
if self.hash.startswith(target):
return # بلاک معتبر پیدا شد!
self.nonce += 1
مرحله ششم — استفاده واقعی از UTXO Set
(txid, output_index) → output نگه میداریم. وقتی Alice یک خروجی را خرج میکند، از مجموعه حذف و خروجیهای جدید اضافه میشوند:
("abc123...", 0) → Alice : 100
("def456...", 0) → Bob : 30
("def456...", 1) → Alice : 70
# موتور اصلی: کیف پول، استخراج و اعتبارسنجی کامل
MiniBitcoin کنار هم میگذاریم. این کلاس مجموعه UTXO را از روی زنجیره بازسازی میکند، پرداخت میسازد (با باقیپول خودکار)، تراکنشهای در انتظار را با پاداش Coinbase استخراج میکند و کل زنجیره را بهطور کامل اعتبارسنجی میکند — شامل تشخیص Double Spend:
class MiniBitcoin:
def __init__(self, difficulty=3, reward=50,
genesis_address="Alice",
genesis_amount=100):
self.difficulty = difficulty
self.reward = reward
genesis_tx = Transaction(
[],
[TxOutput(genesis_address, genesis_amount)]
)
self.genesis = Block(
0, [genesis_tx], "0" * 64,
timestamp=0
)
self.genesis.hash = (
self.genesis.calculate_hash()
)
self.chain = [self.genesis]
self.pending = []
def _utxos(self):
# کل زنجیره را دوباره پخش میکنیم و
# مجموعه خروجیهای خرجنشده را میسازیم.
utxos = {}
for block in self.chain:
for tx in block.transactions:
for tx_input in tx.inputs:
key = (tx_input.txid,
tx_input.output_index)
utxos.pop(key, None) # خرج شد
for index, output in enumerate(tx.outputs):
utxos[(tx.txid, index)] = output
return utxos
def balance(self, address):
return sum(
output.amount
for output in self._utxos().values()
if output.address == address
)
def create_payment(self, sender, recipient, amount):
if amount <= 0:
raise ValueError("amount must be positive")
utxos = [(key, output)
for key, output
in self._utxos().items()
if output.address == sender]
total = 0
inputs = []
for (txid, index), output in utxos:
inputs.append(TxInput(txid, index))
total += output.amount
if total >= amount:
break
if total < amount:
raise ValueError("insufficient funds")
outputs = [TxOutput(recipient, amount)]
change = total - amount
if change:
outputs.append(TxOutput(sender, change))
tx = Transaction(inputs, outputs)
self.pending.append(tx)
return tx
def mine_pending(self, miner_address):
# Coinbase: تراکنش پاداش ماینر
reward_tx = Transaction(
[], [TxOutput(miner_address, self.reward)]
)
block = Block(
len(self.chain),
[reward_tx] + self.pending,
self.chain[-1].hash
)
self._validate_candidate_block(block)
block.mine(self.difficulty)
self.chain.append(block)
self.pending = []
return block
def _validate_candidate_block(self, block):
if block.index != len(self.chain):
raise ValueError("invalid block index")
if block.previous_hash != self.chain[-1].hash:
raise ValueError("invalid previous hash")
if block.merkle_root != block.calculate_merkle_root():
raise ValueError("invalid merkle root")
# اولین تراکنش باید Coinbase باشد (بدون ورودی)
if block.transactions[0].inputs:
raise ValueError(
"first transaction must be coinbase"
)
utxos = self._utxos()
spent_in_block = set()
for tx in block.transactions[1:]:
input_total = 0
for tx_input in tx.inputs:
key = (tx_input.txid, tx_input.output_index)
if key in spent_in_block:
raise ValueError("double spend detected")
if key not in utxos:
raise ValueError("missing UTXO")
spent_in_block.add(key)
input_total += utxos[key].amount
output_total = sum(
o.amount for o in tx.outputs
)
if output_total > input_total:
raise ValueError("outputs exceed inputs")
return True
is_valid() کل زنجیره را با همین قوانین پیمایش میکند — بررسی Genesis، هش هدرها، Proof of Work، Coinbase و پخش مجدد همه UTXOها — و یک بولین برمیگرداند. از آن برای آزمایش دستکاری استفاده خواهیم کرد.
# حالا واقعاً از آن استفاده کنیم
coin = MiniBitcoin(difficulty=3, reward=50)
print(coin.balance("Alice"))
# 100 (بلاک پیدایش به Alice صد واحد داد)
coin.create_payment("Alice", "Bob", 30)
# تراکنش وارد pending میشود — هنوز داخل زنجیره نیست
block = coin.mine_pending("Miner")
# ماینر بلاک میسازد، Proof of Work انجام میدهد، بلاک را اضافه میکند
print(coin.balance("Alice")) # 70
print(coin.balance("Bob")) # 30
print(coin.balance("Miner")) # 50
# قسمت جالب: اگر بلاک را دستکاری کنیم چه میشود؟
Alice → Bob : 30 را تبدیل کند به Alice → Bob : 999. داده تراکنش تغییر کرد → txid تغییر میکند → Merkle Root تغییر میکند → Hash بلاک تغییر میکند → بلاک دیگر معتبر نیست:
print("Valid:", coin.is_valid())
# Valid: True
# کسی بیسروصدا تاریخچه را بازنویسی میکند:
coin.chain[1].transactions[1].outputs[0] = (
TxOutput("Bob", 999)
)
print("Valid:", coin.is_valid())
# Valid: False
Previous Hash = هش قدیمی بلاک ۱ را نگه داشته است. مهاجم باید بلاک ۱ را دوباره استخراج کند، بعد بلاک ۲، بعد همه بلاکهای بعدی — یعنی همه Proof of Workها را دوباره انجام دهد. زنجیرهکردن Hashها همراه با Proof of Work دقیقاً چیزی است که هزینه تغییر تاریخچه را بالا میبرد.
# هنوز یک چیز خیلی مهم کم داریم: رمزنگاری و شبکه
address = "Alice" نیست. اگر کسی ادعا کند Alice است، برنامه ما حرفش را قبول میکند. در دنیای واقعی این کافی نیست — و اینجاست که کلید خصوصی، کلید عمومی و امضای دیجیتال وارد میشوند:
- هش بلاک با هدر میخواند
- هش به هدف سختی رسیده
- Previous Hash درست است
- هیچ خروجیای دوبار خرج نشده
# بیتکوین یک پشته از ایدههاست، نه یک اختراع واحد
| قابلیت | نمونه ما | Bitcoin واقعی |
|---|---|---|
| Block | ✓ | ✓ |
| Previous Hash | ✓ | ✓ |
| SHA-256 | ✓ | ✓ |
| Merkle Root | ✓ | ✓ |
| Proof of Work | ✓ | ✓ |
| پاداش استخراج | ✓ | ✓ |
| UTXO | ✓ | ✓ |
| بررسی Double Spend | ✓ | ✓ |
| امضای دیجیتال | ✕ | ✓ |
| کلید خصوصی/عمومی | ✕ | ✓ |
| شبکه P2P | ✕ | ✓ |
| اجماع کامل | سادهشده | ✓ |
| Bitcoin Script | ✕ | ✓ |
| تنظیم سختی واقعی | ✕ | ✓ |
| کارمزد تراکنش | ✕ | ✓ |
# چرا ساختن یک نمونه کوچک ارزش دارد؟
در کنار هم قرار گرفتن آنهاست.
اجزای ساده + قوانین دقیق = سیستمِ پیچیده



