atlasarzdigital

آموزش قدم به قدم ساخت یک بلاک چین ساده با python

آموزش قدم به قدم ساخت  یک بلاک چین ساده با python

اگر شما اینجایید ، احتمالا مثل من مجنون ارزهای دیجیتال و بلاک چین هستید ، و می خواهید بدانید که سیستم بلاک چین چگونه کار می کند و تکنولوزی بنیادین پشت آن چیست.

اما فهم سیستم های بلاک چینی ساده نیست یا حداقل برای من اینطور نبود. من در فیلم های عمیقی ازهم پاشیدم، آموزش های مختلف زیادی را بررسی کردم و در مواجهه با مثال های اندک دچار ناامیدی زیادی نیز شدم.

من یادگیری را به همراه عمل دوست دارم. این کار مرا در مرحله کد مجبور به مواجهه با صورت مسئله می کند. اگر شما هم همین کار را انجام دهید در پایان این آموزش یک سیستم بلاک چین فعال دارید به علاوه درک صحیحی از نحوه عملکرد آن.

قبل از شروع…

یاد آور می شوم که بلاک چین یک زنجیره متوالی از رکورد های تغییرناپذیر است که بلاک (block) نامیده می شوند. محتویات این بلاک ها میتواند شامل اطلاعات معاملات یا فایل یا هرچیز دیگری که فکر میکنید یا می خواهید باشد. اما مهم ترین چیز این است که این بلاک ها بصورت متوالی و زنجیره وار با استفاده از هش (hash) به یکدیگر وصلند. اگر در مورد hash اطلاعات کافی ندارید می توانید به این لینک مراجعه کنید و توضیح مختصری درباره آن بخوانید.

این آموزش به درد چه کسی میخورد؟

 شما باید به زبان python آشنایی داشته باشید بخصوص نحوه تعریف و استفاده از class ها، همچنین آشنایی با نحوه کار پروتکل http (مثلا چه نوع درخواست هایی مبتنی بر بستر http وجود دارد و چگونه کار میکنند) به دلیل اینکه ما با بلاک چین خودمان از طریق پروتکل http مکاتبه و تعامل خواهیم داشت.

برنامه ها وکتابخانه های پیش نیاز:

  • Python v3.6+
  • Flask
  • Requests

کد نهایی را از اینجا می توانید دانلود کنید.

گام اول: ساخت یک بلاک چین

نرم افزار ویرایش متن (text editor) یا IDE مورد علاقه خود را باز کنید. یک فایل جدید بنام “blockchain.py” ایجاد کنید . ما فقط از یک فایل استفاده خواهیم کرد. اما اگر چیزی را گم کردید یا از دست دادید میتوانید به سورس کد برنامه مراجعه کنید.

پیاده سازی یک بلاک چین

ما یک کلاس بنام “Blockchain” خواهیم ساخت که متد سازنده ( __init__ )  آن دو لیست خالی اولیه ایجاد می کند که یکی برای ذخیره زنجیره های بلاک هایمان استفاده می شود و دیگری برای ذخیره ی تراکنش ها. نمونه اولیه کد کلاس ما:

class Blockchain(object):
    def __init__(self):
        self.chain = []
        self.current_transactions = []
        
    def new_block(self):
        # ایجاد بلاک جدید و اضافه کردن آن به زنجیره
        pass
    
    def new_transaction(self):
        # اضافه کردن تراکنش جدید به لیست تراکنش ها
        pass
    
    @staticmethod
    def hash(block):
        # هش کردن یک بلاک
        pass

    @property
    def last_block(self):
        # بازگرداندن آخرین بلاک در زنجیره
        pass

کلاس “Blockchain” ما برای مدیریت زنجیره، پاسخگو است. این کلاس تراکنش ها را ذخیره می کند و تعدادی متد های کمکی برای اضافه کردن بلاک های جدید به زنجیره دارد.

ساختار یک بلاک چه شکلی ست؟

هر بلاک شامل یک شماره (index)، یک برچسب زمانی در قالب سیستم زمانی یونیکس (unix timestamp)، یک لیستی از تراکنش ها (transactions)، یک پروف (proof) و در نهایت هش (hash) بلاک قبلی می باشد.

مثالی از کد بلاک مورد نظر ما :

block = {
    'index': 1,
    'timestamp': 1506057125.900785,
    'transactions': [
        {
            'sender': "8527147fe1f5426f9dd545de4b27ee00",
            'recipient': "a77f5cdfa2934df3954a5c7c7da5df1f",
            'amount': 5,
        }
    ],
    'proof': 324984774000,
    'previous_hash': "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"
}

در این نقطه ایده ی زنجیره باید آشکار باشد بدین صورت که هر بلاک، هش بلاک قبلی را در خود دارد. این مسله خیلی حیاتی ست چرا که همین عامل باعث تغییرناپذیریه سیستم بلاک چین می شود. اگر یک حمله کننده (attacker) یکی از بلاک های قبلی در زنجیره را دستکاری یا خراب کند متعاقبا هش همه بلاک های بعد از آن بلاک دستکاری شده، دیگر درست نخواهند بود.

آیا این روش معقول است؟ اگر نه کمی بیشتر وقت بگذارید و روی این موضوع فکر کنید. هسته ی ایده ی پشت بلاک چین همین خاصیت است.

اضافه کردن تراکنش ها به بلاک

ما به روشی نیازمندیم جهت اضافه کردن تراکنش ها به یک بلاک. انجام این کار به عهده ی متد “new_transaction” است:

class Blockchain(object):
    ...
    
    def new_transaction(self, sender, recipient, amount):
        """
        در این متد یک تراکنش جدید ایجاد میشود تا درون بلاک ماین شده ی بعدی ذخیره شود

        :param sender: <str> آدرس فرستنده
        :param recipient: <str> آدرس گیرنده
        :param amount: <int> مقداری که قرار است جابجا شود
        :return: <int> شماره بلاکی که اطلاعات این تراکنش را درخود جای خواهد داد
        """

        self.current_transactions.append({
            'sender': sender,
            'recipient': recipient,
            'amount': amount,
        })

        return self.last_block['index'] + 1

بعد از اینکه متد “new_transaction”  یک تراکنش را به لیست اضافه کرد شماره بلاکی که تراکنش به آن اضافه خواهد شد را برمی گرداند که همان بلاک بعدی می شود که باید استخراج (mine) شود. این کار برای موارد بعدی که شخصی تراکنشی ارسال می کند مفید خواهد بود.

ساخت بلاک های جدید

وقتی از روی کلاس “Blockchain”  ما یک نمونه (instance) ایجاد شد، باید یک بلاک اولیه که آن را “genesis” یا “منشأ” می نامیم، درونش ایجاد کنیم. درواقع با بلاک اولیه بذردهی اش میکنیم. همچنین باید به بلاک اولیه مان یک پروف (proof) اضافه کنیم که نتیجه و جوابش همان نتیجه mine کردن می شود که به آن اثبات کار (proof of work) هم میگیوییم.

خوب ما کد ایجاد بلاک اولیه مان (genesis) را در متد سازنده ( __init__ ) کلاسمان خواهیم نوشت و علاوه بر آن متدهای دیگر را هم بنام های “new_block”، “new_transaction” و “hash” تکمیل خواهیم نمود:

import hashlib
import json
from time import time


class Blockchain(object):
    def __init__(self):
        self.current_transactions = []
        self.chain = []

        # ساخت بلاک اولیه
        self.new_block(previous_hash=1, proof=100)

    def new_block(self, proof, previous_hash=None):
        """
        ساخت بلاک جدید در زنجیره بلاک چین

        :param proof: <int> پروف داده شده توسط الگوریتم اثبات کار
        :param previous_hash: (Optional) <str> هش بلاک قبلی
        :return: <dict> بلاک جدید
        """

        block = {
            'index': len(self.chain) + 1,
            'timestamp': time(),
            'transactions': self.current_transactions,
            'proof': proof,
            'previous_hash': previous_hash or self.hash(self.chain[-1]),
        }

        # خالی کردن لیست کنونی تراکنش ها
        self.current_transactions = []

        self.chain.append(block)
        return block

    def new_transaction(self, sender, recipient, amount):
        """
        Creates a new transaction to go into the next mined Block

        :param sender: <str> آدرس فرستنده
        :param recipient: <str> آدرس گیرنده
        :param amount: <int> مقدار
        :return: <int> شماره بلاکی که اطلاعات این تراکنش را درخود جای خواهد داد
        """
        self.current_transactions.append({
            'sender': sender,
            'recipient': recipient,
            'amount': amount,
        })

        return self.last_block['index'] + 1

    @property
    def last_block(self):
        return self.chain[-1]

    @staticmethod
    def hash(block):
        """
        از روی اطلاعات یک بلاک SHA-256 ساخت هش از نوع

        :param block: <dict> Block
        :return: <str> (hex) هش بلاک در قالب هگز 
        """

        # باید حتما اطلاعات بلاک را قبل از عملیات هش مرتب سازی کنیم
		       # تا با هش های نابرابر برای بلاک های با اطلاعات یکسان مواجه نشویم
        block_string = json.dumps(block, sort_keys=True).encode()
        return hashlib.sha256(block_string).hexdigest()

ما تقریبا کد بلاک چینمان را تمام کردیم. اما در این نقطه شما باید از چگونگی ساخت بلاک ها، جعل و استخراج شدنشان در تعجب باشید.

درک الگوریتم اثبات کار (Proof of Work)

یک الگوریتم اثبات کار (PoW) مشخص می کند که چطور بلاک ها در بلاک چین ساخته یا استخراج می شوند. هدف PoW کشف عددی برای حل یک مسله است. این عدد توسط هر شخصی در شبکه می تواند تولید شود و به زبان محاسباتی باید پیدا کردنش سخت ولی تاییدش راحت باشد. هسته ی ایده ی پشت PoW همین است.

خوب برای درک PoW یک مثال ساده خواهیم زد:

بیایید فرض کنیم که انتهای هش یک عدد صحیح x ضربدر عدد صحیح دیگری بنام y باید به صفر ختم شود. بنابراین:

Hash(x*y) = ac23dc…….0

حالا برای این مثال ساده x را عدد ثابت 5 در نظر میگیریم (x=5). پیاده سازی این مثال در python :

from hashlib import sha256

x = 5
y = 0  #  !چه عددی باید باشد y ما هنوز نمی دانیم که

while sha256(f'{x*y}'.encode()).hexdigest()[-1] != "0":
    y += 1

print(f'The solution is y = {y}')

نتیجه این کد می شود y=21 . زیرا انتهای هش حاصلضرب 5 و 21 به صفر ختم شد:

hash(5 * 21) = 1253e9373e...5e3600155e860

در بیت کوین الگوریتم PoW ، Hashcash نامیده می شود و این الگوریتم تفاوت چندانی با مثال ساده ی بالای ما ندارد. الگوریتم PoW ، باعث ایجاد مسابقه بین ماینرها می شود تا بتوانند بلاک جدید ایجاد کنند. به طور کلی میزان سختی الگوریتم براساس تعداد کاراکترهایی که در یک رشته جستجو می شوند مشخص می شود. سپس ماینرها بدلیل زحمتی که برای حل الگوریتم و بدست آوردن جواب کشیدند به عنوان جایزه  یک ارز (coin) در قالب یک تراکنش دریافت می کنند.

شبکه هم به سادگی می تواند جوابی که بدست آورده اند را تایید یا رد کند.

پیاده سازی الگوریتم PoW پایه

بیایید یک الگوریتم مشابه برای بلاک چینمان ایجاد کنیم. روش کار ما مشابه روش مثال بالا خواهد بود:

یافتن عدد ‘p که وقتی در کنار عدد نتیجه پروف بلاک قبلی قرار گرفت و هش شد، 4 عدد صفر در ابتدای هش جدید تولید شود

import hashlib
import json

from time import time
from uuid import uuid4


class Blockchain(object):
    ...
        
    def proof_of_work(self, last_proof):
        """
        :ساده PoW یک الگوریتم
         - شامل 4 عدد صفر در ابتدایش باشد hash(pp') به طوری که p' یافتن عدد 
         - جواب پروف برای بلاک جدید می باشد p' نتیجه پروف بلاک قبلی می باشد و p عدد

        :param last_proof: <int>
        :return: <int>
        """

        proof = 0
        while self.valid_proof(last_proof, proof) is False:
            proof += 1

        return proof

    @staticmethod
    def valid_proof(last_proof, proof):
        """
        چهار عدد صفر در ابتدایش دارد؟ hash(last_proof, proof) تایید اعتبار: آیا

        :param last_proof: <int> پروف بلاک قبلی
        :param proof: <int> پروف فعلی
        :return: <bool> برمی گرداند False :در غیر این صورت | True :در صورت درستی
        """

        guess = f'{last_proof}{proof}'.encode()
        guess_hash = hashlib.sha256(guess).hexdigest()
        return guess_hash[:4] == "0000"

جهت تنظیم درجه ی سختی الگوریتم ما می توانیم تعداد صفرهای ایتدای هش تولیدی را تغییر دهیم. اما تعداد 4 مناسب است. خودتان خواهید فهمید که اضافه کردن یک عدد صفر بیشتر به ابتدای نتیجه هش نهایی باعث ایجاد تفاوت زمانی بسیار زیادی نسبت به حالت قبلی جهت یافتن جواب می شود.

خوب کلاس ما تقریبا کامل است و ماهم آماده ایم که تعامل با آن را از طریق پروتکل http آغاز کنیم.

 

گام دوم: بلاک چین ما به عنوان یک API

ما میخواهیم که از فریمورک “Flask” استفاده کنیم. “Flask” یک فریمورک کوچکی ست جهت تسهیل در وصل شدن (map) آدرس های وب به توابع python. این فریمورک به ما اجازه می دهد تا با بلاک چینمان با استفاده از درخواست های مبتنی بر بستر پروتکل “http” ارتباط برقرار کنیم.

ما سه متد ایجاد خواهیم کرد:

  • /transactions/new : جهت ساخت یک تراکنش جدید و اضافه کردن آن به یک بلاک
  • /mine : برای این که به سرورمان بگوییم که یک بلاک جدید را استخراج (mine) کند
  • /chain : جهت برگرداندن لیست کامل بلاک های بلاک چین

اعمال تنظیمات Flask

سرور ما یک گره (node) را در شبکه بلاک چین تشکیل خواهد داد. کد این کار:

 

import hashlib
import json
from textwrap import dedent
from time import time
from uuid import uuid4

from flask import Flask


class Blockchain(object):
    ...


# از روی گره مان (Instantiate) نمونه سازی اولیه 
app = Flask(__name__)

# برای این گره (global) ایجاد یک آدرس یکتای جهانی
node_identifier = str(uuid4()).replace('-', '')

# نمونه سازی اولیه از بلاک چین
blockchain = Blockchain()


@app.route('/mine', methods=['GET'])
def mine():
    return "We'll mine a new Block"
  
@app.route('/transactions/new', methods=['POST'])
def new_transaction():
    return "We'll add a new transaction"

@app.route('/chain', methods=['GET'])
def full_chain():
    response = {
        'chain': blockchain.chain,
        'length': len(blockchain.chain),
    }
    return jsonify(response), 200

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

حال توضیحات مختصری شرح خواهیم داد در مورد این که در کد بالا چه چیزهایی اضافه کردیم:

  • خط 15: یک نمونه سازی اولیه از گره مان انجام دادیم. حهت اطلاعات بیشتر در مورد Flask می توانید به این آدرس مراجعه کنید.
  • خط 18: ایجاد یک نام تصادفی برای گره مان
  • خط 21: نمونه سازی اولیه از روی کلاس “Blockchain”
  • خط 24-26: ساخت آدرس (URI) /mine که درخواست ها را در قالب GET دریافت می کند
  • خط 28-30: ساخت آدرس (URI) /transactions/new که درخواست ها را به صورت POST دریافت می کند، بدلیل این که اطلاعات (Data) به این آدرس ارسال خواهیم کرد
  • خط 32-38: ساخت آدرس (URI) /chain که کار آن بازگرداندن اطلاعات کامل بلاک چین به ما است
  • خط 40-41: سرور را بر روی پورت شماره 5000 راه اندازی می کند

 

گلوگاه (endpoint) تراکنش ها در سرور

ساختار درخواست برای یک تراکنش مانند شکل زیر است و این چیزی ست که یوزر به سرور ارسال خواهد کرد:

{
 "sender": "my address",
 "recipient": "someone else's address",
 "amount": 5
}

چون در حال حاضر ما متد لازم برای اضافه کردن تراکنش ها به یک بلاک را داریم ادامه کار راحت است. بیایید تابع لازم برای اضافه کردن تراکنش ها را بنویسیم:

import hashlib
import json
from textwrap import dedent
from time import time
from uuid import uuid4

from flask import Flask, jsonify, request

...

@app.route('/transactions/new', methods=['POST'])
def new_transaction():
    values = request.get_json()

    # چک کردن فیلدهای اجباری در دیتای پست
    required = ['sender', 'recipient', 'amount']
    if not all(k in values for k in required):
        return 'Missing values', 400

    # ایجاد یک تراکنش جدید
    index = blockchain.new_transaction(values['sender'], values['recipient'], values['amount'])

    response = {'message': f'Transaction will be added to Block {index}'}
    return jsonify(response), 201

گلوگاه (endpoint) ماینینگ

بخش گلوگاه و آدرس ماینینگ جایی ست که اتفاقات عجیبی رخ می دهد و راحتم است. این بخش 3 کار انجام می دهد:

  1. محاسبه PoW
  2. جایزه دادن به ماینر (ما) با اضافه کردن یک تراکنش و اعطای یک ارز (coin) به ما
  3. ساختن بلاک جدید با اضافه کردن آن به زنجیره
import hashlib
import json

from time import time
from uuid import uuid4

from flask import Flask, jsonify, request

...

@app.route('/mine', methods=['GET'])
def mine():
    # ما الگوریتم اثبات کار را اجرا می کنیم تا به پروف بعدی برسیم ...
    last_block = blockchain.last_block
    last_proof = last_block['proof']
    proof = blockchain.proof_of_work(last_proof)

    # ما باید به ازای یافتن پروف جایزه دریافت کنیم
    # فرستنده '0' بدین معنی ست که گره فعلی یک ارز استخراج کرده
    blockchain.new_transaction(
        sender="0",
        recipient=node_identifier,
        amount=1,
    )

    # ساخت بلاک جدید با اضافه کردن آن به زنجیره
    previous_hash = blockchain.hash(last_block)
    block = blockchain.new_block(proof, previous_hash)

    response = {
        'message': "New Block Forged",
        'index': block['index'],
        'transactions': block['transactions'],
        'proof': block['proof'],
        'previous_hash': block['previous_hash'],
    }
    return jsonify(response), 200

توجه کنید که گیرنده بلاک استخراج شده (mine شده) آدرس گره ماست و بیشتر کارهایی که ما اینجا انجام دادیم فقط تعامل با متدهای کلاس Blockchain مان بود. خوب ما کارمان تمام شده و می توانیم ارتباط و تعامل با بلاک چین مان را آغاز کنیم.

گام سوم: برقراری ارتباط با بلاک چین مان

شما می توانید از cURL قدیمی یا نرم افزار Postman برای ارتباط با API مان از طریق شبکه استفاده کنید.

با این دستور سرورمان را اجرا می کنیم:

$ python blockchain.py
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

خوب بیایید بخش استخراج بلاک را از طریق ارسال درخواست نوع GET به آدرس http://localhost:5000/mine تست کنیم :

ایجاد درخواست GET با استفاده از postman

حال بیایید ایجاد یک تراکنش جدید را با ارسال درخواست از نوع POST به آدرس http://localhost:5000/transactions/new که در بدنه (body) آن اطلاعاتی با ساختار تراکنش مان وجود دارد را تست کنیم:

ارسال درخواست از نوع post با postman

اگر شما از postman استفاده نمی کنید می توانید درخواست معادل را با استفاده از cURL ساخته و ارسال کنید:

$ curl -X POST -H "Content-Type: application/json" -d '{
 "sender": "d4ee26eee15148ee92c6cd394edd974e",
 "recipient": "someone-other-address",
 "amount": 5
}' "http://localhost:5000/transactions/new"

من سرور را رستارت (restart) کردم و دو بلاک استخراج کردم و با بلاک جایزه ام باید تعداد بلاک ها 3 تا شده باشد. حال بیایید این موضوع را با ارسال درخواست به آدرس http://localhost:5000/chain بررسی کنیم:

{
  "chain": [
    {
      "index": 1,
      "previous_hash": 1,
      "proof": 100,
      "timestamp": 1506280650.770839,
      "transactions": []
    },
    {
      "index": 2,
      "previous_hash": "c099bc...bfb7",
      "proof": 35293,
      "timestamp": 1506280664.717925,
      "transactions": [
        {
          "amount": 1,
          "recipient": "8bbcb347e0634905b0cac7955bae152b",
          "sender": "0"
        }
      ]
    },
    {
      "index": 3,
      "previous_hash": "eff91a...10f2",
      "proof": 35089,
      "timestamp": 1506280666.1086972,
      "transactions": [
        {
          "amount": 1,
          "recipient": "8bbcb347e0634905b0cac7955bae152b",
          "sender": "0"
        }
      ]
    }
  ],
  "length": 3
}

گام چهارم: اجماع و توافق

کار جالبی بود. ما در حال حاضر یک سیستم بلاک چین ساده داریم که تراکنش هایی را قبول می کند و به ما اجازه استخراج بلاک ها را می دهد. اما کل هدف سیستم های بلاک چین این است که نامتمرکز (decentralized) باشند و اگر نامتمرکز هستند چطور روی زمین ما مطمعن باشیم که همه آن ها یک زنجیره یکسان را نشان می دهند؟ این مورد را مشکلات اجماع (problem of Consensus) می نامند. به همین دلیل اگر ما بخواهیم که بیشتر از یک گره در شبکه داشته باشیم باید یک الگوریتم توافق پیاده سازی کنیم.

ثبت گره های جدید

قبل از این که بخواهیم الگوریتم اجماع را پیاده سازی کنیم باید روشی بیابیم که از طریق آن یک گره بتواند گره های همسایه اش را در شبکه شناسایی کند و بشناسد. هر گره در شبکه باید دفتری از اطلاعات (registry) گره های دیگر در شبکه را داشته باشد. پس ما گلوگاه های (endpoint) بیشتری برای این کار لازم داریم:

  1. /nodes/register : جهت قبول کردن لیستی از گره های جدید در قالب مجموعه ای از URL ها
  2. /nodes/resolve : جهت پیاده سازی الگوریتم اجماع که هرگونه تضاد و مغایرت را برطرف می کند تا به یک گره اطمینان دهد که زنجیره درست را دارد

خوب برای این کار باید متد آغازگر کلاس “Blockchain” را تغییر دهیم و متدی را ایجاد کنیم برای ثبت گره ها:

...
from urllib.parse import urlparse
...


class Blockchain(object):
    def __init__(self):
        ...
        self.nodes = set()
        ...

    def register_node(self, address):
        """
        اضافه کردن گره جدید به لیست گره ها

        :param address: <str>  'http://192.168.0.5:5000' :آدرس گره - مثال
        :return: None
        """

        parsed_url = urlparse(address)
        self.nodes.add(parsed_url.netloc)

توجه کنید که ما از یک دستور set() جهت نگهداری لیست گره ها استفاده کرده ایم. این کار ارزان ترین روش است جهت اطمینان از این که اضافه شدن گره های جدید آگاهانه است به این معنی که دیگر مهم نیست که یک گره مشخص را چندبار به سیستم اضافه کرده ایم و آن گره دقیقا فقط یکبار ثبت می شود.

پیاده سازی الگوریتم اجماع

همان طور که اشاره شد، برخورد و تضاد زمانی رخ می دهد که زنجیره یک گره با زنجیره گره دیگر متفاوت باشد. جهت حل این مسله ما قانونی ایجاد می کنیم که براساس آن طولانی ترین زنجیره صحیح و بدون اشکال الویت دارد بر زنجیره های دیگر و معتبر است (longest valid chain is authoritative). با استفاده از این قانون ما به اجماع در بین گره های درون شبکه دست میابیم.

...
import requests


class Blockchain(object)
    ...
    
    def valid_chain(self, chain):
        """
        مشخص می کند که آیا زنجیره بلاک ها معتبر است یا نه

        :param chain: <list> A blockchain
        :return: <bool> True if valid, False if not
        """

        last_block = chain[0]
        current_index = 1

        while current_index < len(chain):
            block = chain[current_index]
            print(f'{last_block}')
            print(f'{block}')
            print("n-----------n")
            # هش بلاک را جهت درستی بررسی می کند
            if block['previous_hash'] != self.hash(last_block):
                return False

            # بلاک جهت درستی بررسی می شود PoW
            if not self.valid_proof(last_block['proof'], block['proof']):
                return False

            last_block = block
            current_index += 1

        return True

    def resolve_conflicts(self):
        """
        این بخش الگوریتم اجماع ما است که با جایگزین کردن
        طولانی ترین زنجیره در شبکه تضادها را برطرف می کند

        :return: <bool> True if our chain was replaced, False if not
        """

        neighbours = self.nodes
        new_chain = None

        # طول زنجیره خودمان را بدست می آوریم
        max_length = len(self.chain)

        # گرفتن زنجیره های همه گره های دیگر و بررسی درستی آن ها
        for node in neighbours:
            response = requests.get(f'http://{node}/chain')

            if response.status_code == 200:
                length = response.json()['length']
                chain = response.json()['chain']

                # بررسی می کنیم که آیا طول این زنجیره طولانی تر است و همچنین معتبر است یا نه
                if length > max_length and self.valid_chain(chain):
                    max_length = length
                    new_chain = chain

        # اگر یک زنجیره معتبر طولانی تر از زنجیره خودمان یافتیم آن را بروی زنجیره خودمان جایگزین می کنیم
        if new_chain:
            self.chain = new_chain
            return True

        return False

 

کار متد valid_chain() چک کردن اعتبار زنجیره است. بدین صورت که در تک تک بلاک های زنجیره دو مقدار هش و پروف آن بلاک را چک می کند.

کار متد resolve_conflicts() چک کردن گره های همسایه و دانلود و تایید زنجیره آن ها بوسیله متد بالاست. اگر یک زنجیره معتبر پیدا شود آن زنجیره که بلاک های بیشتری نسبت به زنجیره ما دارد بر روی زنجیره ما جایگزین می شود.

خوب حالا بیایید دو گلوگاه (endpoint) در api مان ایجاد کنیم. یکی برای اضافه کردن گره های همسایه و دیگری برای حل تضاد:

@app.route('/nodes/register', methods=['POST'])
def register_nodes():
    values = request.get_json()

    nodes = values.get('nodes')
    if nodes is None:
        return "Error: Please supply a valid list of nodes", 400

    for node in nodes:
        blockchain.register_node(node)

    response = {
        'message': 'New nodes have been added',
        'total_nodes': list(blockchain.nodes),
    }
    return jsonify(response), 201


@app.route('/nodes/resolve', methods=['GET'])
def consensus():
    replaced = blockchain.resolve_conflicts()

    if replaced:
        response = {
            'message': 'Our chain was replaced',
            'new_chain': blockchain.chain
        }
    else:
        response = {
            'message': 'Our chain is authoritative',
            'chain': blockchain.chain
        }

    return jsonify(response), 200

خوب حال شما می توانید این سیستم را روی یک رایانه دیگر راه اندازی کنید و گره های متفاوتی را ایجاد کنید یا اینکه سیستم را با استفاده از پورت های متفاوت بروی همین رایانه پردازش کنید. من یک گره دیگر روی رایانه فعلیم با شماره پورتی متفاوت ایجاد کردم و آن را با گره فعلیم ثبت نمودم. پس در حال حاضر من دو گره دارم:

http://localhost:5000  و http://localhost:5001

ایجاد گره جدید

سپس تعدادی بلاک جدید را با دو گره استخراج نمودم تا مطمعن شوم که زنجیره طولانی تر شده. بعد از آن آدرس GET /nodes/resolve را روی گره اول، فراخوانی نمودم.

جایی که زنجیره براساس الگوریتم اجماع جایگزین می شود:

 

الگوریتم اجماع در عمل

خوب کار تمام است. حالا بروید سراغ دوستانتان و با کمکشان سیستم بلاک چینتان را تست کنید.

من امیدوارم که این آموزش الهامی برای شما باشد جهت ساختن چیزی جدید. من از تولد ارزهای دیجیتال مسرورم چرا که معتقدم بلاک چین ها به سرعت سیستم فکری ما را درباره اقتصاد، دولت ها و ضبط اطلاعات تغییر خواهند داد.

41
دیدگاه کاربران

avatar
Photo and Image Files
 
 
 
Audio and Video Files
 
 
 
Other File Types
 
 
 
25 رشته دیدگاه‌ها
16 پاسخ‌های
8 دنبال‌کنندگان
 
دیدگاه با بیشترین واکنش‌
داغ‌ترین رشته دیدگاه
28 نویسندگان دیدگاه‌ها
سلیمان نمازیZeynabfatemiجعفر روزبانmohammad mahmoodiمایا قربانی نویسندگان اخیر دیدگاه‌ها
سلیمان نمازی
سلیمان نمازی

سلام آیا ممکنه از بلاک چین رمز ارزهای دیگر مانند بیت کوین و غیره و یا هر بلاک چین دیگر ، جهت رمز ارز جدید استفاده کنیم؟ و اگر چنین چیزی ممکنه میشه توضیح بدید.

Zeynabfatemi
Zeynabfatemi

بسیار عاااااالی.اجرکم عندالله

جعفر روزبان
جعفر روزبان

سلام درود به شرفت که این اطلاعات ارزشمند رو برای عموم در سایت قرار دادی با این سرعتی که تکنولوژی داره پیش میره واقعا معنی پول درآوردن و کارکردن میشه گفت تا چند سال دیگه عوض میشه و نسل جدید بعید میدونم حاضر باشن با قوانین کار و حقوق وزارت کاری ایی مشغول بکار شن چقدر خوبه که ما هم بتونیم در جهت پیشرفت و ارتقا سطح و سواد رسانه ای این نوع درآمد و کسب و کار رو هم یاد بگیریم من ۴۰ سالمه و هرچی میگذره بیشتر به این امر ایمان پیدا میکنم که ۵ تا ۱۰ سال دیگه کیف پول الکترونیکی یکی از پر کاربرد ترین موارد تراکنش شده در مراکز خرید بشه وقتی ۱۵ سال پیش گفتن باید کارت عابر بانک داشته باشید تا حقوقتون رو واریز کنیم خیلی از افراد مخصوصا بازنشته ها مقاومت میکردن و این کار رو ایمن نمی دونستن ولی الان که سال ۹۸ شده هر کسی حداقل ۴ تا ۵ تا کارت عابر بانک داره پیش بینی ها درست از آب درمیاد فقط کمی اجبار باید وجود داشته باشه ممنونم از اینکه وقت گذاشتین در ضمن افتخار میکنم که هموطنای باسوادی مثل شما تو مملکتون هست

mohammad mahmoodi
mohammad mahmoodi

بسیار عالی و مفید واقعا زحمت کشیدید ممنونم

مایا قربانی
مایا قربانی

سلام جناب مهندس. باسپاس از مقاله بی نظیرتون، امکان داره تو پیاده سازی عملی این کار کمکم کنید؟ فرصت زیادی ندارم حدودا یک هفته. هزینشم جسارتا تقبل می کنم. ممنون میشم ایمیل بزنید.

بهزاد
بهزاد

چطور اینو تبدیل به یک ارز دیجیتال کنیم

leila985
leila985

سلام گام سوم چطور باید به سرور وصل شد میشه کامل بگید که چه کار باید بکنم

علی
علی

باریکلا خیلی کیف کردم مطلب کامل و قابل هضمی بود … مرسی

محمد غیاثوند
محمد غیاثوند

یعنی میشه یه والت اینترنتی اختصاصی ساخت؟!با این روش

امیر آقایی
امیر آقایی

واقعا نه تنها این مطلب کلیه مطالب سایت فوق العاده هستن
بسیار سپاسگزارم

بازخورد
feedback
بازخورد شما درباره ارزدیجیتال

این بازخورد برای صفحه آموزش قدم به قدم ساخت یک بلاک چین ساده با python ارسال خواهد شد.

گزارش خطا
  • گزارش خطا
  • انتقادات و پیشنهادات
  • نیاز به راهنمایی

ارزهای دیجیتاللیست کامل
اخبار و مقالاتاخبار و مقالات بیشتر
صرافی ارزهای دیجیتالصرافی های بیشتر
دستگاه ماینر ارزهای دیجیتالدستگاه های بیشتر
موردی یافت نشد.