وبلاگ فربد | Farbod Blog

توی این وبلاگ راجع به پروژه هام صحبت می کنم

ساخت blockchain با استفاده از پایتون

  • ۳۰۷

سلام دوستان :)

توی پست امروز قراره ببینیم که بلاکچین چی هست و چطور کار میکنه و در گام بعدی هم با استفاده از زبان برنامه نویسی پایتون یک سیستم blockchain ساده پیاده سازی کنیم و بعد هم با ساخت یک REST API با استفاده از فریم ورک flask اون رو قابل استفاده کنیم.

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

بلاکچین چیست؟

در سال 2008 میلادی، یک نویسنده(یا نویسنده ها) با نام جعلی Satoshi Nakamoto یک مقاله درباره یک سیستم پول الکترونیک نظیر به نظیر که برای تضمین امنیتش نیاز به هیچ تاییدیه شخص ثالثی نداره و به جاش، زمان هر تبادل ثبت میشه و بعد hash میشه و بعد به زنجیره ای از همین hash ها اضافه میشه، متنشر کردن.

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

یک بلاک چین باید این ویژگی ها رو داشته باشه:

۱- تغییر ناپذیر

۲- غیرقابل هک شدن

۳- پایدار و ماندگار

۴- توزیع شده

این ویژگی ها برای پایداری بلاکچین و امنیت شبکه در تبادلاتی که انجام میشه لازم هست.

خب، حالا بریم با هم یک شبکه بلاکچین رو با استفاده از پایتون پیاده سازی کنیم. برای ساده نگه داشتن کار، ما فرض میکنیم که داده ای که میخوایم توی بلاکچین ذخیره کنیم، اطلاعات یک تبادل هست.

توی بلاکچین مبحث دیگه ای به اسم proof-of-work وجود داره. در واقع یک کاربر میتونه یک بلاک رو دستکاری کنه و بعد بلاک های بعدی رو دوباره محاسبه کنه و یک زنجیره معتبر دیگه ایجاد کنه! برای جلوگیری از این مشکل ما به چیزی به نام proof-of-work نیاز داریم.

سیستم proof-of-work، انجام کار مورد نیاز برای ایجاد یک بلوک جدید رو به تدریج دشوارتر می کنه. این به این معنیه که شخصی که یک بلوک قبلی رو اصلاح می‌کنه باید کار بلوک و همه بلوک‌های بعد از اون رو دوباره انجام بده. سیستم proof-of-work نیاز به اسکن برای مقداری داره که هنگام hash با تعداد معینی بیت صفر شروع میشه. این مقدار به عنوان  مقدار nonce شناخته میشه. تعداد بیت های صفر پیشرو به عنوان سختی شناخته میشه. میانگین کار مورد نیاز برای ایجاد یک بلوک به صورت تصاعدی با تعداد بیت‌های صفر اصلی افزایش پیدا میکنه، و بنابراین، با افزایش سختی هر بلوک جدید، میتونیم به اندازه کافی از تغییر بلوک‌های قبلی توسط کاربران جلوگیری کنیم، چون انجام مجدد بلوک‌های بعدی عملا غیرممکنه.

پیش نیاز ها:

برای این که این بلاک چین رو برای همه قابل استفاده کنیم، باید یک سرور داشته باشیم که از آدرس اون استفاده کنیم. سرور رو یا باید خریداری کنیم و یا از سرویس های مجانی runtime مثل activestate استفاده کنیم. اما میتونیم برای همه قابل استفادش نکنیم و روی یک شبکه داخلی(اینترانت) استفادش کنیم.

اینجا برای ذخیره اطلاعات از فرمت استاندارد JSON استفاده می کنیم:

{   
    "author": "author_name",
    "timestamp": "transaction_time", 
    "data": "transaction_data"
}

و برای ساخت API هم از Flask استفاده میکنیم پس اول از همه باید کتابخونه Flask رو نصب کنیم.

برای نصب این کتابخونه توی ویندوز وارد cmd بشید و دستور زیر رو وارد کنید:

pip install Flask

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

sudo pip3 install Flask

خب حالا باید یک فایل بسازیم که کد ها رو داخلش بنویسیم.

کد:

from hashlib import sha256
import json
import time

from flask import Flask, request
import requests


class Block:
    def __init__(self, index, transactions, timestamp, previous_hash):
        self.index = index
        self.transactions = transactions
        self.timestamp = timestamp
        self.previous_hash = previous_hash
        self.nonce = 0

    def compute_hash(self):
        """
        A function that return the hash of the block contents.
        """
        block_string = json.dumps(self.__dict__, sort_keys=True)
        return sha256(block_string.encode()).hexdigest()


class Blockchain:
    # difficulty of our PoW algorithm
    difficulty = 2

    def __init__(self):
        self.unconfirmed_transactions = []
        self.chain = []
        self.create_genesis_block()

    def create_genesis_block(self):
        """
        A function to generate genesis block and appends it to
        the chain. The block has index 0, previous_hash as 0, and
        a valid hash.
        """
        genesis_block = Block(0, [], time.time(), "0")
        genesis_block.hash = genesis_block.compute_hash()
        self.chain.append(genesis_block)

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

    def add_block(self, block, proof):
        """
        A function that adds the block to the chain after verification.
        Verification includes:
        * Checking if the proof is valid.
        * The previous_hash referred in the block and the hash of latest block
          in the chain match.
        """
        previous_hash = self.last_block.hash

        if previous_hash != block.previous_hash:
            return False

        if not self.is_valid_proof(block, proof):
            return False

        block.hash = proof
        self.chain.append(block)
        return True

    def is_valid_proof(self, block, block_hash):
        """
        Check if block_hash is valid hash of block and satisfies
        the difficulty criteria.
        """
        return (block_hash.startswith('0' * Blockchain.difficulty) and
                block_hash == block.compute_hash())

    def proof_of_work(self, block):
        """
        Function that tries different values of nonce to get a hash
        that satisfies our difficulty criteria.
        """
        block.nonce = 0

        computed_hash = block.compute_hash()
        while not computed_hash.startswith('0' * Blockchain.difficulty):
            block.nonce += 1
            computed_hash = block.compute_hash()

        return computed_hash

    def add_new_transaction(self, transaction):
        self.unconfirmed_transactions.append(transaction)

    def mine(self):
        """
        This function serves as an interface to add the pending
        transactions to the blockchain by adding them to the block
        and figuring out Proof Of Work.
        """
        if not self.unconfirmed_transactions:
            return False

        last_block = self.last_block

        new_block = Block(index=last_block.index + 1,
                          transactions=self.unconfirmed_transactions,
                          timestamp=time.time(),
                          previous_hash=last_block.hash)

        proof = self.proof_of_work(new_block)
        self.add_block(new_block, proof)

        self.unconfirmed_transactions = []
        return new_block.index


app = Flask(__name__)
blockchain = Blockchain()



@app.route('/chain', methods=['GET'])
def get_chain():
    chain_data = []
    for block in blockchain.chain:
        chain_data.append(block.__dict__)
    return json.dumps({"length": len(chain_data),
                       "chain": chain_data})



app.run(debug=True, port=5000)

توضیح:

خب اول از همه کتابخونه hashlib رو برای hash کردن اطلاعاتی که میخوایم ذخیره کنیم import کردیم. اینجا برای hash کردن از الگوریتم sha256 استفاده می کنیم. بعد کتابخونه json رو برای فرمت دهی به ذخیره اطلاعات و کتابخونه time رو برای timestamp کردن اطلاعات import کردیم. بعد هم کتابخونه های flask و requests رو برای ساخت import ،API کردیم.

بعد از اینکه کتابخونه های مورد نیازمون رو import کردیم باید بریم سراغ خود برنامه. اول از همه یک کلاس به اسم block تعریف میکنیم که نشون دهنده هر بلاک توی بلاکچین ما هست. هر بلاک یک اندیس، یک لیست از تبادلات و یک nonce(که برای proof-of-work هست که بالاتر توضیح دادیم) داره. و همچنین یک تابع هم داره که یک hash از تمام اطلاعات داخل بلاک برمیگردونه.

بعد از کلاس block باید یک کلاس blockchain تعریف کنیم که یک سری از بلاک ها رو داخلش ذخیره کنیم. این کلاس حاوی متد هایی برای ساختن بلاک، اضافه کردن بلاک به بلاکچین، صحت سنجی بلاک و proof-of-work و اضافه کردن تبادل جدید و محاسبه بلاک های جدید هست.

بعد از اینکه کلاس ها رو تعریف کردیم، بلاکچین خودمون رو براساس کلاس Blockchain که تعریف کرده بودیم ایجاد میکنیم.

حالا که بلاکچین رو درست کردیم توی سروری که با Flask ایجاد کردیم یک مسیر به اسم chain درست می کنیم که یک خروجی JSON از بلاکچین ما برمیگردونه.

در نهایت هم سرور Flask رو اجرا میکنیم.

 

خب تبریک میگم:)) ما تونستیم الان یک بلاکچین ایجاد کنیم و حالا میتونیم هرجوری که میخوایم ازش استفاده کنیم. برای اینکه امتحانش کنید هم میتونید فایل رو اجرا کنید و با استفاده از curl یا هر دستور دیگه ای روی localhost و پورت 5000 امتحانش کنید.

البته حواستون باشه که یک وقت اینو برای ساخت یک crypto استفاده نکنید! چون که به الگوریتم های پیشرفته تری هم نیاز داره. ولی برای کار های دیگه میشه استفاده کرد.

 

امیدوارم براتون مفید بوده باشه D:


نظرات: (۰) هیچ نظری هنوز ثبت نشده است
ارسال نظر آزاد است، اما اگر قبلا در بیان ثبت نام کرده اید می توانید ابتدا وارد شوید.
شما میتوانید از این تگهای html استفاده کنید:
<b> یا <strong>، <em> یا <i>، <u>، <strike> یا <s>، <sup>، <sub>، <blockquote>، <code>، <pre>، <hr>، <br>، <p>، <a href="" title="">، <span style="">، <div align="">
تجدید کد امنیتی