توسعه بلاک چین برای صنعت با استفاده از Go. قسمت 1

اکنون چهار ماه است که روی پروژه ای به نام «توسعه ابزارهای حفاظت و مدیریت داده ها در بخش های دولتی و صنعتی مبتنی بر بلاک چین» کار می کنم.
اکنون می خواهم در مورد نحوه شروع این پروژه به شما بگویم و اکنون کد برنامه را به طور کامل شرح می دهم.

توسعه بلاک چین برای صنعت با استفاده از Go. قسمت 1

این اولین مقاله از مجموعه مقالات است. در اینجا سرور و پروتکل را توضیح می دهم. در واقع، خواننده حتی می تواند نسخه های خود را از این عناصر بلاک چین بنویسد.

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

سال گذشته، در هکاتون Digital Breakthrough، آنها ایده ای برای ساختن یک سیستم مفید برای صنعت و اقتصاد دیجیتال با استفاده از فناوری دفتر کل توزیع شده ارائه کردند؛ همچنین کمک هزینه ای برای توسعه توسط صندوق کمک به نوآوری صادر شد (من باید جداگانه بنویسم. مقاله در مورد کمک هزینه، برای کسانی که به تازگی استارت آپ ها را راه اندازی کرده اند)، و اکنون به ترتیب.

توسعه در زبان Go انجام می شود و پایگاه داده ای که بلوک ها در آن ذخیره می شوند LevelDB است.
بخش‌های اصلی پروتکل، سرور (که TCP و WebSocket را اجرا می‌کند - برای مثال اولی برای همگام‌سازی بلاک چین، دومی برای اتصال مشتریان، ارسال تراکنش‌ها و دستورات از جاوا اسکریپت).

همانطور که گفته شد، این بلاک چین در درجه اول برای خودکارسازی و محافظت از مبادله محصولات بین تامین کنندگان و مشتریان یا هر دو در یک شخص مورد نیاز است. این افراد عجله ای برای اعتماد به یکدیگر ندارند. اما وظیفه تنها ایجاد یک "چک" با یک ماشین حساب داخلی نیست، بلکه سیستمی است که اکثر کارهای معمولی را که هنگام کار با چرخه عمر محصول ایجاد می شود، خودکار می کند. بایت کدی که مسئول این موضوع است، همانطور که در بلاک چین ها مرسوم است، در ورودی ها و خروجی های تراکنش ها ذخیره می شود (خود تراکنش ها در بلوک ها ذخیره می شوند، بلوک ها در LevelDB از قبل در قالب GOB کدگذاری شده اند). ابتدا اجازه دهید در مورد پروتکل و سرور (معروف به گره) صحبت کنیم.

پروتکل پیچیده نیست، تمام هدف آن این است که در پاسخ به یک خط فرمان خاص، به حالت بارگیری برخی از داده ها، معمولاً یک بلوک یا تراکنش، بروید، و همچنین برای تبادل موجودی مورد نیاز است، به طوری که گره بداند چه کسی است. به آن متصل است و چگونه باید کار انجام دهند (گره های متصل شده برای جلسه همگام سازی "همسایه" نیز نامیده می شوند زیرا IP آنها مشخص است و داده های وضعیت آنها در حافظه ذخیره می شود).

پوشه ها (دایرکتوری ها همانطور که لینوکس آنها را نامیده است) در درک برنامه نویسان Go بسته نامیده می شوند، بنابراین در ابتدای هر فایل با کد Go از این دایرکتوری می نویسند بسته folder_name_where_this_file is located. در غیر این صورت، نمی توانید بسته را به کامپایلر تغذیه کنید. خوب، این برای کسانی که این زبان را می دانند پنهان نیست. این بسته ها هستند:

  • ارتباطات شبکه (سرور، کلاینت، پروتکل)
  • ساختارهای داده های ذخیره شده و ارسال شده (بلاک، تراکنش)
  • پایگاه داده (بلاک چین)
  • اجماع، وفاق
  • ماشین مجازی انباشته (xvm)
  • کمکی (کریپتو، انواع) که فعلاً تمام است.

این لینک به github است

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

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

زیرروال سرور به عنوان یک سرور داده عمل می کند که در بالای پروتکل TCP با استفاده از ساختارهای داده از بسته پروتکل اجرا می شود.

روال از بسته های زیر استفاده می کند: سرور, پروتکل, انواع. در خود بسته tcp_server.go شامل ساختار داده خدمت.

type Serve struct {
	Port string
	BufSize int
	ST *types.Settings
}

می تواند پارامترهای زیر را بپذیرد:

  • پورت شبکه که از طریق آن داده ها مبادله می شود
  • فایل پیکربندی سرور با فرمت JSON
  • پرچم برای اجرا در حالت اشکال زدایی (بلاک چین خصوصی)

پیش رفتن:

  • پیکربندی را از فایل JSON می خواند
  • پرچم حالت اشکال زدایی بررسی می شود: اگر تنظیم شود، زمانبندی همگام سازی شبکه راه اندازی نمی شود و زنجیره بلوکی بارگیری نمی شود.
  • راه اندازی ساختار داده های پیکربندی و راه اندازی سرور

سرور

  • راه اندازی سرور TCP و تعامل شبکه را مطابق با پروتکل انجام می دهد.
  • دارای یک ساختار داده Serve متشکل از یک شماره پورت، یک اندازه بافر و یک اشاره گر به ساختار است انواع. تنظیمات
  • متد Run تعامل شبکه را شروع می کند (گوش دادن به اتصالات ورودی در یک پورت معین، هنگامی که یک اتصال جدید دریافت می شود، پردازش آن به روش دسته خصوصی در یک رشته جدید منتقل می شود)
  • В دسته داده های اتصال به یک بافر خوانده می شود، به یک نمایش رشته تبدیل می شود و به آن ارسال می شود پروتکل.انتخاب
  • پروتکل.انتخاب برمی گرداند نتیجه یا باعث خطا می شود. نتیجه سپس به پروتکل.تفسیرکه برمی گردد intrpr - شی از نوع InterpreteData، یا باعث ایجاد خطا در پردازش نتیجه انتخاب می شود
  • سپس سوئیچ اجرا می شود intrpr.Commands[0] که یکی از موارد زیر را بررسی می کند: نتیجه، inv، خطا و یک بخش وجود دارد به طور پیش فرض
  • در بخش نتیجه سوئیچ با مقدار پیدا می شود intrpr.Commands[1] که مقادیر را بررسی می کند طول بافر и نسخه (در هر مورد تابع مربوطه فراخوانی می شود)

توابع GetVersion и طول بافر در پرونده هستند srvlib.go بسته سرور

GetVersion(conn net.Conn, version string)

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

conn.Write([]byte("result:" + version))

.
تابع

BufferLength(conn net.Conn, intrpr *protocol.InterpreteData)

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

  • نوع داده های مشخص شده در پروتکل را که باید پذیرفته شوند، روی کنسول چاپ می کند:
    fmt.Println("DataType:", intrpr.Commands[2])
  • ارزش را می خواند intrpr.Body به یک متغیر عددی buf_len
  • بافر ایجاد می کند newbuf اندازه مشخص شده:
    make([]byte, buf_len)
  • یک پاسخ خوب ارسال می کند:
    conn.Write([]byte("result:ok"))
  • به طور کامل بافر را از جریان خوانده شده پر می کند:
    io.ReadFull(conn, newbuf)

    .

  • محتویات بافر را روی کنسول چاپ می کند
    fmt.Println(string(newbuf))

    و تعداد بایت های خوانده شده

    fmt.Println("Bytes length:", n)
  • یک پاسخ خوب ارسال می کند:
    conn.Write([]byte("result:ok"))

روش‌های بسته سرور برای پردازش داده‌های دریافتی با استفاده از توابع از بسته پیکربندی شده‌اند پروتکل.

پروتکل

یک پروتکل به عنوان وسیله ای عمل می کند که داده ها را در تبادل شبکه نشان می دهد.

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

  • رشته ورودی با استفاده از سر و بدن تقسیم می شود ReqParseN2 (خ)
  • head به عناصر تقسیم می شود و با استفاده از ReqParseHead (head) در یک برش فرمان قرار می گیرد.
  • В سوئیچ (دستورات[0]) دستور دریافتی را انتخاب کنید (cmd، کلید، آدرس یا بخش فعال می شود به طور پیش فرض)
  • 2 دستور در cmd بررسی می شود سوئیچ (فرمان‌ها[1]) - طول и انحراف.
  • طول نوع داده را بررسی می کند دستورات[2] و آن را در آن ذخیره می کند نوع داده
  • آن را بررسی می کند بدن حاوی یک مقدار رشته است
    len(body) < 1
  • رشته پاسخ را برمی گرداند:
    "result:bufferlength:" + datatype + "/" + body
  • انحراف یک رشته را برمی گرداند
    return "result:version/auto"

مترجم

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

type InterpreteData struct {
	Head string
	Commands []string
	Body string
	IsErr bool
	ErrCode int 
	ErrMessage string
}

تابع

Interprete(str string) (*InterpreteData, error)

رشته ای را می پذیرد نتیجه و یک ارجاع به شی ایجاد می کند و برمی گرداند InterpreteData.

پیش رفتن:

  • به طور مشابه انتخاب سر و بدن با استفاده از آن استخراج می شود ReqParseN2 (خ)
  • با استفاده از سر به عناصر تقسیم می شود ReqParseHead (سر)
  • شی مقداردهی اولیه می شود InterpreteData و یک اشاره گر به آن برگردانده می شود:

res := &InterpreteData{
	Head: head,
	Commands: commands,
	Body: body,
}
return res, nil

این شیء در server.go بسته اصلی

مشتری

بسته مشتری شامل توابع است TCPConnect и TCPResponseData.

تابع

TCPConnect(s *types.Settings, data []byte, payload []byte)

اینگونه کار می کند:

  • یک اتصال به اتصال مشخص شده در شیء تنظیمات ارسال شده برقرار می شود
    net.Dial("tcp", s.Host + ":" + s.Port)
  • داده های ارسال شده در پارامتر داده منتقل می شود:
    conn.Write(data)
  • پاسخ خوانده می شود
    resp, n, _ := TCPResponseData(conn, s.BufSize)

    و روی کنسول چاپ می شود

    fmt.Println(string(resp[:n]))
  • در صورت انتقال ظرفیت ترابری سپس آن را منتقل می کند
    conn.Write(payload)

    و همچنین پاسخ سرور را می خواند و آن را در کنسول چاپ می کند

تابع

 TCPResponseData(conn net.Conn, bufsiz int) ([]byte, int, error)

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

زیر برنامه مشتری

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

می‌تواند پارامترهای زیر را بپذیرد: فایل پیکربندی با فرمت JSON، داده‌هایی که به عنوان رشته به سرور ارسال می‌شوند، مسیر فایل برای ارسال به بار، پرچم شبیه‌سازی زمان‌بندی گره، نوع داده‌ای که به عنوان مقدار عددی منتقل می‌شود.

  • دریافت پیکربندی
    st := types.ParseConfig(*config)
  • اگر پرچم emu پاس شود، شروع می شود شلیک کننده
  • اگر پرچم f نشان دهنده مسیر فایل ارائه شده باشد، داده های آن را در آن بارگذاری می کنیم fdb و محتوا به سرور ارسال می شود
    client.TCPConnect(st, []byte(CMD_BUFFER_LENGTH + ":" + strconv.Itoa(*t) + "/" + strconv.Itoa(fdblen)), fdb)
  • اگر فایل مشخص نشده باشد، داده های پرچم به سادگی ارسال می شود -d:
    client.TCPConnect(st, []byte(*data), nil)

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

در قسمت دوم در مورد ساختارهای داده برای بلوک ها و تراکنش ها، در 3 در مورد سرور WebSocket برای اتصال از جاوا اسکریپت، در قسمت 4 به زمانبندی همگام سازی، سپس یک ماشین پشته که بایت کدها را از ورودی ها و خروجی ها پردازش می کند، رمزنگاری و استخر برای خروجی ها

منبع: www.habr.com

اضافه کردن نظر