آدرس

تهران، خیابان شریعتی، بالاتر از سه راه ملک، روبروی آتش نشانی

شماره تماس

۰۹۱۹۳۴۲۶۲۵۱
۰۲۱۹۱۳۰۳۴۲۴

آدرس ایمیل

info@artarasaneh.com
artarasaneh@gmail.com

نصب و راه‌اندازی Chaincode آماده Asset Transfer Basic در هایپرلجر فابریک

نصب و راه‌اندازی Chaincode آماده Asset Transfer Basic در هایپرلجر فابریک

فرض کن یک اپلیکیشن وب داریم که می‌خواهد مالکیت یک دارایی را تغییر دهد. کاربر دکمهٔ «انتقال دارایی» را می‌زند و اپلیکیشن می‌خواهد این تغییر در بلاک‌چین ثبت شود. از اینجا داستان شروع می‌شود.

در قدم اول، اپلیکیشن (client) یک پیشنهاد تراکنش می‌سازد که شامل نام تابع chaincode (مثلاً TransferAsset) و آرگومان‌ها (مثلاً شناسهٔ دارایی و نام مالک جدید) است. اما به‌جای اینکه بلافاصله این درخواست را به ordering service بفرستد، ابتدا آن را به تعدادی از peers می‌فرستد تا آن‌ها «پیشنهاد» را اجرا کنند و بگویند آیا خروجی پیشنهادی مطابق منطق قرارداد است یا نه. این اجرا در واقع شبیه یک «پیش‌اجرا»ست: chaincode بر روی peerها اجرا می‌شود ولی نتیجهٔ این اجرا هنوز تغییر دائمی در ledger ایجاد نمی‌کند — در عوض peerها یک‌سری اطلاعات تولید می‌کنند که به آن‌ها می‌گوییم read set و write set؛ یعنی کلیدهایی که خوانده شده‌اند و مقادیری که قرار است نوشته شوند. هر peer این نتیجهٔ پیش‌اجرا را امضا می‌کند — این امضا و خروجی‌ها همان «endorsement» یا تائیدیه‌اند.

پس از اینکه client از peers کافی (طبق policy سازمانی) امضاها را گرفت، یک تراکنشِ کامل شامل payload اصلی، read/write sets و مجموعهٔ endorsements ساخته می‌شود. این تراکنشِ بسته‌بندی‌شده آمادهٔ ارسال به ordering service است. حالا زمان آن است که تراکنش به orderer فرستاده شود — اینجاست که میگوییم «Invoke یعنی ارسال تراکنش به Orderer».

ordering service (که در شبکه‌های کوچک معمولاً با Raft پیاده می‌شود) تراکنش‌های دریافتی را دریافت می‌کند و آن‌ها را در قالب یک جریان مرتب قرار می‌دهد. نقش اساسی orderer این است که ترتیب جهانیِ تراکنش‌ها را تعیین کند و آن‌ها را در قالب بلاک‌هایی بسته‌بندی کند؛ به زبان ساده، orderer مثل یک منشی است که تراکنش‌ها را پشت سر هم می‌چیند و هر از چندی آن‌ها را به شکل یک بلاک تحویل می‌دهد. این مرحله هیچ‌گاه منطق قرارداد یا اعتبار نهایی تراکنش را بررسی نمی‌کند — تنها ترتیب و توالی را تضمین می‌کند.

وقتی که یک بلاک ساخته شد، orderer آن بلاک را به تمام peers عضو کانال ارسال (deliver) می‌کند. اینجا نقش peers دوباره برجسته می‌شود؛ هر peer بلاک را دریافت می‌کند و باید تصمیم بگیرد که آیا تراکنش‌های داخل بلاک را قابل درج در دفترکل می‌داند یا نه. برای این کار، هر peer مراحل «اعتبارسنجی و commit» را اجرا می‌کند. اعتبارسنجی شامل بررسی این است که آیا endorsementsِ دریافتی برای هر تراکنش مطابق با policy مورد انتظار است یا نه، و مهم‌تر از آن، بررسی شرطی به نام MVCC (Multi-Version Concurrency Control) انجام می‌شود: peer چک می‌کند که مقادیری که در زمان پیش‌اجرا خوانده شده‌اند، از زمان آن اجرا تا الان تغییر نکرده باشند. اگر خواندن و نوشتن تغییرات دیگری بین زمان اجرا و زمان اعتبارسنجی رخ داده باشد (یعنی وضعیت همزمانی باعث ناسازگاری شده)، تراکنش رد می‌شود چون دیگر تضمین می‌شود که write set آن با وضعیت فعلی همخوانی ندارد. تنها تراکنش‌هایی که از اعتبارسنجی عبور کنند، وارد مرحلهٔ commit می‌شوند.

در مرحلهٔ commit، peer دو کار اصلی انجام می‌دهد: ابتدا بلاک را در قسمت Blockchain ذخیره می‌کند؛ یعنی خودِ بلوکِ باینری به صورت append-only نگهداری می‌شود تا تاریخچهٔ کامل تراکنش‌ها باقی بماند. این همان «تاریخچهٔ کامل» است — هر بلوک، شامل header، data و metadata است که به‌صورت دائمی نگهداری می‌شود. سپس، برای هر تراکنشِ معتبر، peer World State را به‌روزرسانی می‌کند؛ World State نمایِ فعلیِ داده‌هاست، یک snapshot سریع از آخرین مقادیر برای هر کلید. در Fabric این World State می‌تواند با LevelDB به‌صورت یک پایگاه کلید-مقدار ساده یا با CouchDB به‌صورت JSON document نگهداری شود. این تفاوت در پایگاهِ داده روش‌های جستجو و query را تغییر می‌دهد، مثلاً CouchDB امکان rich query با JSON را می‌دهد.

همین‌جا توجه کن که به‌خاطر تقسیم مسئولیت‌ها، ترتیب و اطمینان در Fabric بسیار شفاف است: client مسئول پیشنهاد و جمع‌آوری endorsements است، orderer مسئول ترتیب و بسته‌بندی است، و peers مسئول اطمینان از معتبر بودن و نگه‌داری ledger و world state. این جداسازی باعث می‌شود که شبکه بتواند همزمان مقیاس‌پذیر باشد و هم کنترل دقیقی روی سیاست‌های امضا و اعتبار اعمال کند.

از منظر عملیاتی، وقتی یک تراکنش موفق commit می‌شود، معمولاً peerها یک Event تولید می‌کنند (رویدادی که اپلیکیشن‌ها می‌توانند به آن subscribe کنند) تا اپلیکیشن از موفقیت تراکنش باخبر شود و UI یا منطق بالادستی را آپدیت کند. اگر تراکنش ناموفق شود (مثلاً endorsement policy پاس نشد یا conflict در MVCC رخ داد)، آن تراکنش در بلاک ثبت می‌شود اما در وضعیت invalid نشانه‌گذاری می‌گردد و World State تغییری نمی‌کند؛ بنابراین تاریخچهٔ کامل نشان می‌دهد که آن تراکنش مورد پردازش قرار گرفته اما معتبر نبوده است.

 

مرحله 0

مرحله 1

مفهوم Chaincode چیست؟

Chaincode در Hyperledger Fabric همان Smart Contract (قرارداد هوشمند) است.
این کد روی Peer nodes اجرا می‌شود و تعریف می‌کند که چه داده‌هایی در ledger ذخیره شوند و چه قوانینی برای تغییر آن داده‌ها وجود دارد و چه کسی مجاز است تراکنش‌ها را اجرا کند و به زبان ساده چین کد مغز بلاک‌چین است؛ همان جایی که منطق برنامه شما قرار دارد.

پروژه‌های نمونهٔ Fabric در مسیر زیر هستند:

fabric-samples/
└── asset-transfer-basic/
     ├── chaincode-go/
     ├── chaincode-javascript/
     ├── chaincode-java/
     └── application-gateway/

برای شروع، ما از نسخهٔ Go استفاده می‌کنیم:

fabric-samples/asset-transfer-basic/chaincode-go

 این پوشه شامل فایل‌های مهم زیر است:

  • chaincode.go → کد اصلی Chaincode
  • go.mod و go.sum → تنظیمات وابستگی‌ها
  • تابع‌های اصلی مثل InitLedger, CreateAsset, ReadAsset, UpdateAsset, DeleteAsset

 اجرای دستورات نصب Chaincode : برو به دایرکتوری شبکه تست:

cd fabric-samples/test-network

اکنون شبکه باید در حال اجرا باشد (اگر نیست، با این دستور بالا بیارش):

./network.sh up createChannel -c mychannel -ca

Deploy Chaincode

Hyperledger Fabric نسخه‌های جدید (v2.x به بالا) از lifecycle جدید برای chaincode استفاده می‌کند.
این مرحله را با اسکریپت آماده اجرا می‌کنیم:

./network.sh deployCC -ccn basic -ccp ../asset-transfer-basic/chaincode-go -ccl go
بخشمعنی
-ccn basicنام chaincode
-ccp ../asset-transfer-basic/chaincode-goمسیر کد chaincode
-ccl goزبان chaincode (Go)

این دستور به صورت خودکار کارهای زیر را انجام می‌دهد:

بسته‌بندی chaincode  دستور داخلی:

peer lifecycle chaincode package basic.tar.gz --path ../asset-transfer-basic/chaincode-go --lang golang --label basic_1

نصب روی Peerها :  هر سازمان chaincode را روی peer خود نصب می‌کند.

Approve توسط هر سازمان : هر سازمان موافقت خود را برای استفاده از این chaincode اعلام می‌کند.

Commit chaincode به کانال :  chaincode رسماً به کانال اضافه می‌شود و قابل استفاده است.

بعد از اجرای دستور بالا، بررسی میکنیم که chaincode واقعاً نصب شده:

docker ps -a

باید کانتینرهایی با نام‌هایی شبیه این ببینید اگر دیدید، یعنی chaincode با موفقیت اجرا شده

dev-peer0.org1.example.com-basic_1-xxxx

تست chaincode

برای اجرای یک تراکنش ساده از chaincode:

./network.sh invoke

این باید لیستی از دارایی‌های نمونه (assets) برگرداند که در تابع InitLedger ساخته شده‌اند.


docker exec cli peer chaincode query -C mychannel -n basic -c '{"Args":["GetAllAssets"]}'

تمرین عملی :

دستور ./network.sh deployCC را اجرا کنید.

با docker ps -a کانتینر chaincode را شناسایی کنید.

با دستور query داده‌های اولیه را بخوانید.

سپس دستور زیر را برای اضافه کردن دارایی جدید اجرا کنید:

docker exec cli peer chaincode invoke -C mychannel -n basic -c '{"function":"CreateAsset","Args":["asset8","car","blue","Ali","4000"]}'

دوباره با GetAllAssets بررسی کنید که asset جدید اضافه شده است.

عامل با Chaincode و بررسی Ledger در Hyperledger Fabric

دو نوع عملیات در Chaincode داریم در Fabric دو نوع فراخوانی chaincode داریم:

نوع فراخوانی  query  میباشد و  دستور Fabric  آن به صورت   

peer chaincode query

که   فقط خواندن داده‌ها از ledger، بدون تولید بلاک جدید
Invoke  peer chaincode invoke    اجرای تراکنش و تغییر وضعیت ledger، منجر به تولید بلاک جدید

آماده‌سازی CLI

ابتدا مطمئن شوید شبکه در حال اجراست:

cd fabric-samples/test-network
./network.sh up createChannel -c mychannel -ca

اگر chaincode را هنوز نصب نکردی:

./network.sh deployCC -ccn basic -ccp ../asset-transfer-basic/chaincode-go -ccl go

اجرای Query (خواندن داده‌ها) : در chaincode نمونه، تابع GetAllAssets داده‌های ledger را برمی‌گرداند.
برای اجرای آن:

docker exec cli peer chaincode query -C mychannel -n basic -c '{"Args":["GetAllAssets"]}'

-C mychannel : نام کانال

-n basic : نام chaincode

-c:  ورودی JSON شامل تابع و آرگومان‌ها

خروجی زیر را میدهد: 

[
 {"ID":"asset1","Color":"blue","Size":5,"Owner":"Tomoko","AppraisedValue":300},
 {"ID":"asset2","Color":"red","Size":5,"Owner":"Brad","AppraisedValue":400},
 ...
]

این دارایی‌ها همان‌هایی هستند که در تابع InitLedger() ساخته شدند.

اجرای Invoke (نوشتن داده جدید) حالا می‌خواهیم یک asset جدید اضافه کنیم:

docker exec cli peer chaincode invoke \
 -o localhost:7050 \
 --ordererTLSHostnameOverride orderer.example.com \
 --tls \
 --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/organizations/ordererOrganizations/example.com/tlsca/tlsca.example.com-cert.pem \
 -C mychannel -n basic \
 -c '{"function":"CreateAsset","Args":["asset8","car","blue","Ali","4000"]}'

 

بخشمعنی
-o localhost:7050ارتباط با Orderer برای ارسال تراکنش
--tls و --cafileاستفاده از TLS برای ارتباط امن
-C mychannelکانال هدف
-n basicنام chaincode
CreateAssetتابع chaincode
"asset8","car","blue","Ali","4000"آرگومان‌های تابع

خروجی درست کد بالا

INFO  [chaincodeCmd] chaincodeInvokeOrQuery -> Chaincode invoke successful. result: status:200

تأیید تغییر در Ledger


حالا با دستور زیر  دوباره داده‌ها را میخوانیم:


docker exec cli peer chaincode query -C mychannel -n basic -c '{"Args":["GetAllAssets"]}'


حالا باید ببینیم که asset جدید (مثلاً asset8) به لیست اضافه شده یا نه 

بررسی Ledger در داخل Peer

Ledger در Peer شامل دو بخش است:

World State (LevelDB یا CouchDB) : وضعیت فعلی داده‌ها

Blockchain (Immutable blocks) :  تاریخچهٔ تمام تراکنش‌ها

برای مشاهدهٔ بلاک‌ها:

docker exec peer0.org1.example.com ls /var/hyperledger/production/ledgersData/chains/chains/mychannel


در آنجا فایل‌هایی مثل:

blockfile_000000
blockfile_000001
blockfile_000002

وجود دارند. هر کدام یک بلاک حاوی تراکنش‌های جدید هستند.

 Query فقط world state را می‌خواند (نه بلاک‌ها).  Invoke تراکنش را به Orderer می‌فرستد، بلاک جدید می‌سازد، Peerها validate و commit می‌کنند. در نتیجه ledger ترکیبی از تاریخچهٔ تغییرات + وضعیت نهایی است.

تمرین عملی

تابع CreateAsset را با مقادیر جدید صدا بزند.

با تابع TransferAsset مالکیت را تغییر دهد:

docker exec cli peer chaincode invoke -C mychannel -n basic -c ‘{"function":"TransferAsset","Args":["asset8","Sara"]}’

دوباره با ReadAsset بررسی کند که مالک تغییر کرده:

docker exec cli peer chaincode query -C mychannel -n basic -c '{"function":"ReadAsset","Args":["asset8"]}'

از طریق docker exec peer0.org1.example.com cat ... یکی از فایل‌های بلاک را بررسی کند تا بفهمد داده‌ها در بلاک ذخیره شده‌اند (باینری هستند، ولی وجود بلاک جدید را می‌بیند).
 

اشتراک گذاری :
مریم گوهرزاد
نویسنده

مریم گوهرزاد

مدرس و بنیانگذار هلدینگ آرتا رسانه. برنامه نویس و محقق حوزه بلاکچین

نظر خودتون رو با ما در میون بزارید

فیلدهای ستاره دار الزامی هستند . ایمیل شما منتشر نمیشود.

https://t.me/artarasaneh
tel:09193426251
https://wa.me/+989193426251
https://instagram.com/artarasaneh_com